https://wiki.ardumower.de/api.php?action=feedcontributions&user=Roland&feedformat=atomwww.wiki.ardumower.de - Benutzerbeiträge [de]2024-03-28T13:40:19ZBenutzerbeiträgeMediaWiki 1.24.1https://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7847Raindancer Firmware (English)2020-08-09T12:00:14Z<p>Roland: /* Overview */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.'''<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. <br />
If the mower reaches the perimeter wire it will continue driving for approx. 20cm. Then the rmower drives back and will be further rotated at a random angle. <br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensorDistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7846Raindancer Firmware (Deutsch)2020-08-09T11:59:51Z<p>Roland: /* Überblick */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden.<br />
Wenn der Mower das Perimeterkabel erreicht, fährt der Roboter noch ca. 20cm weiter. Dann fährt er zurück und dreht sich mit einem Zufallswinkel. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7845Raindancer Firmware (Deutsch)2020-08-09T11:59:25Z<p>Roland: /* Überblick */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden.<br />
Wenn der Mower das Perimeterkabel erreicht, fährt der Roboter noch ca. 20cm weiter. Dann fährt er zurück und dreht sich mit einem Zufallswinkel. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7844Raindancer Firmware (English)2020-08-09T11:58:17Z<p>Roland: /* Overview */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.'''<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. <br />
If the mower reaches the perimeter wire it will continue driving for approx. 20cm. Then the rmower drives back and will be further rotated at a random angle. <br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensorDistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7843Raindancer Firmware (Deutsch)2020-08-09T11:57:51Z<p>Roland: /* Überblick */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden.<br />
Wenn der Mower das Perimeterkabel erreicht, fährt der Roboter noch ca. 20cm weiter. Dann fährt er zurück und dreht sich mit einem Zufallswinkel. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/Ardumower/Raindancer/tree/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7842Raindancer Firmware (English)2020-08-09T11:56:45Z<p>Roland: /* Overview */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.'''<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. <br />
If the mower reaches the perimeter wire it will continue driving for approx. 20cm. Then the rmower drives back and will be further rotated at a random angle. <br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensorDistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7841Raindancer Firmware (Deutsch)2020-08-09T11:56:19Z<p>Roland: /* Überblick */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden.<br />
Wenn der Mower das Perimeterkabel erreicht, fährt der Roboter noch ca. 20cm weiter. Dann fährt er zurück und dreht sich mit einem Zufallswinkel. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/Ardumower/Raindancer/tree/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7840Raindancer Firmware (Deutsch)2020-08-09T11:54:31Z<p>Roland: /* Überblick */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden.<br />
Wenn der Mower das Perimeterkabel erreicht, fährt der Roboter noch ca. 20cm weiter. Dann fährt er zurück und dreht sich mit einem Zufallswinkel. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7839Raindancer Firmware (English)2020-08-09T11:54:29Z<p>Roland: /* Overview */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.'''<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. <br />
If the mower reaches the perimeter wire it will continue driving for approx. 20cm. Then the rmower drives back and will be further rotated at a random angle. <br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7838Raindancer Firmware (Deutsch)2020-08-09T10:47:57Z<p>Roland: /* Weitere Wünsche */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7837Raindancer Firmware (Deutsch)2020-08-09T10:47:43Z<p>Roland: /* Offene Punkte */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7836Raindancer Firmware (Deutsch)2020-08-09T10:47:22Z<p>Roland: /* Mähzonen zwischen aneinander liegenden Flächen */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7835Raindancer Firmware (Deutsch)2020-08-09T10:45:33Z<p>Roland: </p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Raindancer Firmware V1.1.1 (Deutsch)]] '''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7834Raindancer Firmware (Deutsch)2020-08-09T10:43:35Z<p>Roland: </p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Editing Raindancer Firmware V1.1.1 (Deutsch)| Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7833Raindancer Firmware (Deutsch)2020-08-09T10:37:03Z<p>Roland: /* Spiralfahrt */</p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Editing Raindancer Firmware V1.1.1 (Deutsch) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=7832Raindancer Firmware (Deutsch)2020-08-09T10:36:41Z<p>Roland: </p>
<hr />
<div><br />
<br />
'''Die Dokumentation ist für die Firmware Version 2.x.x.'''<br />
<br />
<br />
'''Die Dokumentation für die Version 1.1.1 ist hier [[Editing Raindancer Firmware V1.1.1 (Deutsch) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7831Raindancer Firmware (English)2020-08-09T10:33:40Z<p>Roland: </p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.'''<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]'''<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_V1.1.1_(Deutsch)&diff=7830Raindancer Firmware V1.1.1 (Deutsch)2020-08-09T10:33:21Z<p>Roland: Die Seite wurde neu angelegt: „Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden. =Download= [https://github.com/Ardumower/Raindancer Github Download]…“</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit per.show nochmal das Perimetersignal überprüfen. Mit h oder show.show Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7829Raindancer Firmware (English)2020-08-09T10:31:25Z<p>Roland: /* Archimedean Spiral */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7828Raindancer Firmware (English)2020-08-09T10:30:37Z<p>Roland: /* Mowing zones between adjacent surfaces */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Spiral==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred.<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7827Raindancer Firmware (English)2020-08-09T10:20:32Z<p>Roland: </p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]<br />
<br />
<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Spiral==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7826Raindancer Firmware (English)2020-08-09T10:20:11Z<p>Roland: </p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Spiral==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=7825Raindancer Firmware (English)2020-08-09T10:18:51Z<p>Roland: </p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
'''This documentation is for firmware version 2.x.x.<br />
<br />
<br />
'''The documentation of version 1.1.1 you can find here [[Raindancer Firmware V1.x.x (English) | Raindancer Firmware V1.1.1]]<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approach the charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Spiral==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_V1.x.x_(English)&diff=7819Raindancer Firmware V1.x.x (English)2020-08-09T10:05:56Z<p>Roland: Die Seite wurde neu angelegt: „Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mist…“</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Centrale is used (free with advertising or without advertising for a few euros). In Arduino Centrale, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approach the charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Centrale ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Centrale can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Centrale, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuration. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Centrale go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Centrale commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat.show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Centrale.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with per.show. Disable perimeter output with h or per.show<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is active if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Spiral==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Centrale Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6269Raindancer Firmware (Deutsch)2018-08-12T10:17:43Z<p>Roland: /* Aktivieren der internen Berechnung */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6268Raindancer Firmware (English)2018-08-12T10:16:54Z<p>Roland: /* Enable internal calculation */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:54.08744800,N lon:10.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6267Raindancer Firmware (Deutsch)2018-08-12T10:15:15Z<p>Roland: /* Aktivieren der internen Berechnung */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 53.087448 und Longitude=9.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6266Raindancer Firmware (Deutsch)2018-08-12T10:05:41Z<p>Roland: /* Regen Sensor */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das ausgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6265Raindancer Firmware (English)2018-08-12T10:05:02Z<p>Roland: /* Regen Sensor */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Rain Sensor==<br />
When the robot mows in AUTO mode and it starts to rain, the robot returns to the charging station.<br />
The rain sensor is connected to the designated port of PCB1.3.<br />
The sensitivity of the rain sensor is set on the rain sensor with the potentiometer.<br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
The rain sensor is read out approx. every 1.7 seconds. <br />
<br />
The read out can be displayed with<br />
rain.show<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6264Raindancer Firmware (English)2018-08-12T10:01:58Z<p>Roland: /* Temperature Sensor */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das susgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6263Raindancer Firmware (Deutsch)2018-08-12T09:59:40Z<p>Roland: /* Regen Sensor */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
Wenn der Roboter im AUTO Modus mäht und es anfängt zu regnen, fährt der Roboter in die Ladestation zurück.<br />
Der Regensensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
Die Empfindlichkeit des Regensensors, wird am Regensensor mit dem Poti eingestellt.<br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_RAIN_SERVICE false // Disables rain sensor<br />
<br />
Der Regensensor wird ca. alle 1.7 Sekunden ausgelesen. <br />
<br />
Das susgelesene Ergebnis kann mit <br />
rain.show<br />
angezeigt werden.<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6262Raindancer Firmware (Deutsch)2018-08-12T09:48:18Z<p>Roland: /* Temperatur Sensor */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Regen Sensor==<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6261Raindancer Firmware (English)2018-08-12T09:46:59Z<p>Roland: /* Other wishes */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6260Raindancer Firmware (Deutsch)2018-08-12T09:46:44Z<p>Roland: /* Weitere Wünsche */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6259Raindancer Firmware (Deutsch)2018-07-31T08:31:39Z<p>Roland: /* Kopfladestation */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Regensensor einbinden<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist. Ich schlage daher die Verwendung von schleifenden Kontakten vor.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6258Raindancer Firmware (English)2018-07-31T08:30:04Z<p>Roland: /* Head charging station */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient. I suggest using grinding contacts.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6257Raindancer Firmware (English)2018-07-31T08:21:10Z<p>Roland: /* Through Charging Station */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6256Raindancer Firmware (English)2018-07-31T08:20:51Z<p>Roland: /* Head charging station */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area,0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6255Raindancer Firmware (English)2018-07-31T08:20:31Z<p>Roland: /* Head charging station */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6254Raindancer Firmware (English)2018-07-31T08:20:12Z<p>Roland: /* Head charging station */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
gohome<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6253Raindancer Firmware (English)2018-07-29T16:58:27Z<p>Roland: /* Other wishes */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues. If the perimeter signal is too weak in the middle of the lawn, a GPS area can be configured. If the robot is in this area, it is assumed to be within the perimeter loop.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6252Raindancer Firmware (Deutsch)2018-07-29T16:58:14Z<p>Roland: /* Überblick */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter. Falls das Perimetersignal zu schwach in der Mitte des Rasens ist, kann ein GPS Bereich konfiguriert werden. Wenn sich der Roboter in diesem Bereich befindet, wird angenommen er ist innerhalb der Perimeterschleife.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Regensensor einbinden<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6251Raindancer Firmware (Deutsch)2018-07-29T16:54:22Z<p>Roland: /* Weitere Wünsche */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Regensensor einbinden<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6250Raindancer Firmware (English)2018-07-29T16:54:20Z<p>Roland: /* Other wishes */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6249Raindancer Firmware (Deutsch)2018-07-29T16:53:40Z<p>Roland: /* Offene Punkte */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Regensensor einbinden<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - es kann sein, dass der Mower das Signal in der Mitte des Rasens nicht erkennt, da das Signal zu schwach ist. Man kann dann mit GPS dann sehen, ob man auf der Fläche ist. Wenn man nun sagt, dass das Signal mindesten in 15m Abstand vom Perimeter erkannt werden muss, kann man es innerhalb der Fläche vernachlässigen wenn das GPS Signal anzeigt, das man auf der Fläche ist.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6248Raindancer Firmware (English)2018-07-29T16:53:39Z<p>Roland: /* Open points */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS map - the mower may not recognize the signal in the middle of the lawn because the signal is too weak. You can then use GPS to see if you are on the lawn area. If you now say that the signal must be detected at least 15m away from the perimeter, you can neglect the signal within the area if the GPS signal indicates that you are on the lawn.<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6247Raindancer Firmware (Deutsch)2018-07-29T16:52:28Z<p>Roland: /* Überblick */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter.<br />
<br />
Die Firmware unterstützt eine Kopfladestation und eine Durchgangsladestation. Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* Ausweichen von Objekten, die nahe am Perimeter stehen optimieren (SecondReverse2 im BHT)<br />
* Einseitig befahrbare Ladestation umsetzen<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Regensensor einbinden<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - es kann sein, dass der Mower das Signal in der Mitte des Rasens nicht erkennt, da das Signal zu schwach ist. Man kann dann mit GPS dann sehen, ob man auf der Fläche ist. Wenn man nun sagt, dass das Signal mindesten in 15m Abstand vom Perimeter erkannt werden muss, kann man es innerhalb der Fläche vernachlässigen wenn das GPS Signal anzeigt, das man auf der Fläche ist.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6246Raindancer Firmware (English)2018-07-29T16:52:25Z<p>Roland: /* Overview */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues.<br />
<br />
The firmware supports a head charging station and a through charging station. Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Dodge objects close to the perimeter (SecondReverse2 in the BHT)<br />
* Program one-sided accessible charging station<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS map - the mower may not recognize the signal in the middle of the lawn because the signal is too weak. You can then use GPS to see if you are on the lawn area. If you now say that the signal must be detected at least 15m away from the perimeter, you can neglect the signal within the area if the GPS signal indicates that you are on the lawn.<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(English)&diff=6245Raindancer Firmware (English)2018-07-29T16:37:59Z<p>Roland: /* Charging Station */</p>
<hr />
<div>Folks, English is not my native language. If you don't understand something or find a mistake, please inform me on the forum (name: Roland) or correct the mistake by yourself. Thank you very much.<br />
<br />
<br />
Attention! The software is still changing and can be changed / extended at any time.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(On Github download the Zip-File with the green button)<br />
<br />
The Raindancer firmware is located in the directory code\Raindancer<br />
<br />
The transmitter firmware is located in the directory code\sender<br />
<br />
=Overview=<br />
The Raindancer firmware is based on the code of the Nucleomower which was realized with the development board STM32 Nuleo 411RE in 2016/2017. The firmware was then converted to Ardumower PCB 1.3 in 2017/2018. It pursues the goal of getting a stable system with as little hardware as possible, which works all year round and provides a good mowing result with the chaos principle.<br />
<br />
The firmware has the following '' 'Workflow' '':<br />
The Mower is in the charging station. The Mower drives from the charging station a predetermined distance along the perimeter to an area and then begins to mow after the chaos principle. The mowing time is approx. 130min-150min with the original Ardumowerkomponents. After the battery voltage has dropped to 23.7V, the robot looks for the perimeter cable and drives it to the charging station. Once in the charging station, the battery is charged. The next mowing operation is restarted via the mobile phone with a range command. (The robot can also be operated without a charging station.)<br />
<br />
The firmware was developed for robots with the drive motor rear, but can also be used for the original Ardumower chassis. Optimizations for the original Ardumower chassis will be made later. The mower turns on the perimeter. If a coil has passed over the perimeter cable, the robot will continue driving for approx. 20cm. Then both coils are turned into the loop and from then on it will be further rotated at a random angle. Since the original Ardumower chassis has a short distance between spools and wheels, here is the workaround: In the config.h can be set that the mower drives back a certain way, then turns a fixed angle (rotation simulated on the perimeter) and after the turning the fixed angle, the random angle is rotated.<br />
<br />
Internally in the firmware, distances are traveled in cm. This means that encoders are needed.<br />
<br />
For the '' 'Perimeterrecognition' '' a 128-bit signal is used. Therefore, the Raindancer transmitter (sender) software must be installed on the transmitter. 2 perimeter receivers are needed. As you approach the perimeter cable, the robot slows down.<br />
If the robot does not recognize the signal for 2 seconds, it stops and switches off the motors. If it recognizes the signal again, it continues.<br />
<br />
In the current version, the firmware supports a pass through charging station (supporting a head charging station follows at a later date). Using the charging station can be switched off in the software. Then the robot stops at the perimeter when the battery voltage drops below 23.7V. For charging, the robot can then be switched off, connected to the charging cable and switched on again. The robot then goes into charging mode. If the voltage drops below 21.7V, the undervoltage trip will trip if it is not bypassed.<br />
<br />
With the original motors and wheels, the robot drives at a speed of approx. 1200m / h.<br />
In order to get a reasonable cut, the robot has to mow about 6-9 hours a day for a 1000m² area (my experience). Of course, it also depends on the type and shape of the lawn area.<br />
For acceleration and deceleration, the Simple Trajection Planner is used by the Linux CNC project. This allows a very smooth start and braking.<br />
<br />
If an original Bumperduino, Bumper with switches, Hall Effect sensors, ... are used, they can be connected to the Bumper Pins as before.<br />
<br />
The firmware was optimized for '' 'not with the perimeter wire fenced obstacles' '' on the lawn. Instead of driving at full speed against the obstacle, the speed is reduced from a certain distance and drove gently against the obstacle. Prerequisite for this are sonar sensors. This feature is optional.<br />
The robot supports a self-made Bumperduino with two MaxSonar sonar sensors and an MPX5010DP FREESCALE pressure sensor for a pressure wave hose.<br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
The evaluation is done by an Arduino Nano, which is connected to the PinUserSwitch2 / 3 of the PCB1.3. Upon detection of an obstacle with the sonar sensors, the robot slows down and bumped gently against the obstacle where the bumper or bumper duino triggers.<br />
The board is relatively simple. This allows them to be easily soldered together on a laboratory board. The MaxSonar sensors can be omitted and a separate solution can be connected to the Nano.<br />
The sensor for the pressure wave hose can be omitted and only the sonar sensor is used. Another option for an approach solution is to expand the current Raindancer software.<br />
The original Ardumower ultrasonic sensors are currently not supported. <br />
<br />
The serial interface is used for the operation. On the mobile phone is the software Arduino Central is used (free with advertising or without advertising for a few euros). In Arduino Central, buttons can be configured with commands. The operation is via command line commands. The send line must be terminated with CR. The output is automatic shown on the console or on the mobile phone, depending on where the command was just entered.<br />
Most commands are grouped by services. The group corresponds to the services mentioned in the software. The command following the service is then separated by a dot. Spaces are skipped and have no meaning.<br />
This is useful when using the mobile phone, where a space is inserted after a period.<br />
<br />
Example: clc.enc <br />
The service clc contains the command enc. This addresses the closes loop control service and tells it to show the encoder data.<br />
<br />
Parameters are separated by a comma.<br />
Example: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... does not belong to the command)<br />
This addresses the Positioncontrol service. Drive 60cm at the speed of 30%<br />
<br />
The command H displays the help..<br />
<br />
Many commands shows an output on the console. To disable this output, you can enter h or the same command (which triggered the output).<br />
If an error or motor stall is shown, it can be reset with the reset command.<br />
<br />
The software is modular. The individual modules are hardly influence each otherl. This makes it relatively easy to modify or extend something.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
The UMLET software was used to display and edit the Structure software.<br />
<br />
There is a hardware abstraction layer. All communication with the hardware is done through objects in hardware.h. Most objects in hardware.h are defined in InOutInterface.h. In hardware.cpp the initialization and pin assignment of the hardware takes place.<br />
Services collect data or control the motors and make their service available to the controllogic.<br />
A behavior tree is used for the controllogic. The behavior tree accesses the services via the blackboard. Nodes of the Behavior Tree exchange information about the Blackboard.<br />
<br />
SPLAN was used for the graphic creation of the BHT.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
To view the files of the BHT the following free software can be used:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
The files of the BHT are here:<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
The robot knows two modes: Manual and Auto. In manual mode, all services are running, but the Behavior Tree (BHT) is off. In auto mode, the BHT is activated.<br />
<br />
Which modes will start when:<br />
MANUAL Robot is switched on and is not in the charging station<br />
AUTO The robot is switched on in the charging station and detects a voltage at the charging contacts. Behavior charging is activated. The robot is loading<br />
<br />
If the robot is in MANUAL mode, it can be switched to automode using command A. If the robot then recognizes the perimeter signal, it starts mowing.<br />
<br />
==Open points==<br />
* Stability of the software in the long term. Stand 28.04.2018 Currently, the current software version mowed 63h, has traveled 59km and has rotated 8426 times<br />
* The line tracking algorithm has been recently optimized for the rear wheel drive chassis. Due to the short distance between coil and the wheels of the original Ardumower chassis, it may be necessary to program another algorithm. <br />
* Optimization for the original Ardumower chassis (Mowing works very well with the workaround, if necessary, play with the parameters CONF_PER_CORRECTION_ANGLE and CONF_PERIMETER_DRIVE_BACK_CM)<br />
* Dodge objects close to the perimeter (SecondReverse2 in the BHT)<br />
* Program one-sided accessible charging station<br />
* Use RTC to program start at a defined time<br />
<br />
==Other wishes==<br />
* Integrate rain sensor<br />
* The charging station is currently only counterclockwise approached.<br />
* Amplify the signal of the charging station to + -20V voltage stroke<br />
* SRF08 integration<br />
* Integrate I2C temperature sensors<br />
* An external start / stop button that starts or stops mowing<br />
* Approachthe charging station with GPS. Drive 15m before the charging station on the perimeter and then drive into the charging station..<br />
* GPS map - the mower may not recognize the signal in the middle of the lawn because the signal is too weak. You can then use GPS to see if you are on the lawn area. If you now say that the signal must be detected at least 15m away from the perimeter, you can neglect the signal within the area if the GPS signal indicates that you are on the lawn.<br />
* GPS Map - Note where mower has already mowed. Then mow in less mowed areas if necessary.<br />
The GPS card will probably have to be outsourced to an external processor<br />
<br />
=For minimum commissioning, the following requirements should be met=<br />
<br />
[[File:warning.png]]Safety note: For safety reasons, the mower blades must [[not]] be mounted during the first tests!<br />
<br />
[[File:warning.png]]Important: For the first gearmotor tests, the robot should be jacked up so that the wheels are not in contact with the ground!<br />
<br />
<br />
* PCB1.3 with Arduino DUE<br />
* Original Ardumower drive motors with encoder<br />
* Original Ardumower mowing motor<br />
* Two Ardumower perimeter coils front left / right. Mounted on original Ardumower chassis if necessary: Left / center (depends on which line tracking algorithm one uses)<br />
* BT module<br />
* The bridge for the encoders on the PCB1.3 is bridged to the 2-divider.<br />
* 24V power supply<br />
<br />
=Optional can be used=<br />
* RTC with EEPROM<br />
* Ardumower Bumper Pins with switches, Hall effect sensors, original Bumper Duino, ...<br />
* Pass through charging station<br />
* Self-built Bumperduino with 2MaxSonar sensors on PinUserSwitch2 / 3<br />
<br />
=config.h=<br />
The file config.h contains the basic configuration of the firmware.<br />
<br />
'' 'Before commissioning the parameters must be adjusted.' ''<br />
<br />
Select the chassis form. Only one parameter may be set to true.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
In config.h go then to the code section, which belongs to your choice and change this section.<br />
For the Ardumower chassis the section starts with following:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Console Speed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
If the Bluetooh module has already been configured with the Azurit firmware, the line <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
has to be changed to:<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
<br />
<br />
Setting the wheel circumference and wheel distance. The original Ardumower wheel has a circumference of 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
For the first startup most services should be disabled to prevent error messages:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'' 'ONLY for the original Ardumower chassis design' '' the following constants should be set to optimize the rotation at the perimeter<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Since compiling is done more often, it makes sense to jack up the robot so that the drive wheels and the mower motor can rotate freely.<br />
<br />
After the first compile, upload and start of the firmware, the last line should be:<br />
<br />
Press H for help.<br />
<br />
<br />
Enter H here. Thereafter, all available commands are displayed. It is a good ideas to copy and save the commands to a file, so that you can look at it when you need.<br />
<br />
If after compilation following warning occure, they can be ignored:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
The aim of this chapter is to become more familiar with the operation, and to configure the robot to the extent that the perimeter sensors<br />
work and you can mow within the perimeter.<br />
<br />
The robot is connected via the console cable. Speed: 115200<br />
<br />
==Errorhandling==<br />
If the firmware detects an error, this goes into the Errormode. The Mower stops and the mow motor is switched off. The services continue to run. The first error occurred is latched.<br />
The error is then sent to the console or bluetooth (BT) every 2 seconds, depending on what was last active or activated by sending a character. If you has started the mower via Bluetooth, the error is then shown on BT.<br />
<br />
To disable the error, the following commands must be entered one after the other:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
The error command can be used to display the error log. The error log shows the history of the traversed running nodes of the BHT as well as various other events. It is 5000 characters tall.<br />
error //show errormessage<br />
<br />
The show.hist command displays the last direction of rotation and other parameters.<br />
show.hist //show history<br />
The last entered values will be displayed first, so that they are above!<br />
<br />
<br />
After disabling the error, the Mower can be started again with:<br />
A<br />
However, both coils must be in the perimeter for that.<br />
<br />
==To get warm: Configuration of the battery service==<br />
The battery service determines the voltage of the battery and makes it available to the BHT.<br />
<br />
Activate the battery service in config.h and then re-install the software.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Enter the command:<br />
bat.show<br />
It should display the correct battery voltage.<br />
<br />
If this deviates by more than 0.2V, then this can be adjusted with the constants<br />
#define BATTERYFACTOR_BS 11.0f // Equivalent to (100 + 10) / 10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
These constants are defined in batterySensor.h.<br />
<br />
The voltage in batterySensor.h is calculated as follows<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
== Commissioning of the motors ==<br />
The first thing to check is whether the motors are turning and whether they are turning in the right direction.<br />
For this purpose, the motors are controlled directly with a PWM specification. This means, there is no control of the speed based on the encoder. The speed control loop is open (open loop);<br />
<br />
The command clc.mt, 1,150 causes the clc service to send the input PWM of 150 directly to the motor. Maximum for the PWM is 255.<br />
A 1 controls the left engine, a 2 the right.<br />
<br />
Enter the command:<br />
clc.mt,1,150 <br />
<br />
This activates the motor (1) on the left directly with a PWM of 150.<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
The wheel on the left should turn forward. If it turns backwards, the cable at the plug must be reversed.<br />
Should the wheel not turn, it can still be tried with a higher PWM of e.g. 200.<br />
The wheel should definitely turn even at a PWM of 50 (better less).<br />
<br />
The same for the right wheel (2):<br />
clc.mt,2,150 <br />
<br />
The wheel is then Stopped with:<br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
== Commissioning the encoder ==<br />
It it checked if the encoders work and if they count in the right direction.<br />
<br />
The encoder routine has two counters per wheel. Once an absolute counter (absEnc), which always counts positive no matter in which direction the wheel turns.<br />
And a positive / negative counter (enc), which counts up when driving forward and counts down when reversing.<br />
<br />
Enter the command<br />
clc.mt, 1,150<br />
to make the left wheel turn.<br />
<br />
Enter then<br />
clc.enc<br />
This will display the encoder values from the left and right wheels.<br />
<br />
The output is terminated with the command: h.<br />
<br />
Both displayed counters of the left wheel (1) must now count up.<br />
<br />
Example:<br />
Engine 1 = left - should not count if only the right engine is running.<br />
Engine 2 = right - should not count if only the left engine is running.<br />
! 03, motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m / h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
! 03, motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m / h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
! 03, motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m / h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
! 03, motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m / h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
! 03, motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m / h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
! 03, motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m / h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
! 03, motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m / h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
The example shows that the encoders are counting up. '' 'Example motor 1' '': enc: 972 then enc: 974, then enc: 976 ... '' 'Example motor 2' '': enc: 972 then enc: 975, then enc: 976 ...<br />
<br />
If the enc value counts negative when driving forward you can configure it in the config.h:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
To do this, set CONF_LEFT_ENCODER_INVERSE to true for the left wheel. Set CONF_RIGHT_ENCODER_INVERSE to true for the right wheel.<br />
<br />
Do the same for the right wheel:<br />
clc.mt, 2,150<br />
<br />
Command is stopped with clc.mt, 0,0.<br />
<br />
After the lines in the config.h have been set correctly, recompile, play and retest!<br />
<br />
== Check of the closed loop control service ==<br />
The closed loop control (clc) service controls the speed of a wheel and thus also the straightforward movement of the robot. There is one service for each wheel so there are two services in total. The service internally calculates the speed of the wheel with the aid of the encoder values and then sets the necessary PWM to reach the specified speed (closed loop). The speed is given in%. 100% refering to the constant CONF_MAX_WHEEL_RPM in the config.h.<br />
<br />
With the command clc.v,30 both services are commanded to turn the wheel at a speed (v) of 30%. Thus, both wheels should turn forward.<br />
<br />
Enter:<br />
clc.v, 30 Moving forward with speed 30%<br />
then<br />
clc.v, s stop engine<br />
then<br />
clc.v, -30 drives reverse with speed 30%<br />
<br />
If everything is working, then continue. Otherwise check encoders and drivedirection again.<br />
<br />
mot.cur Shows the motor current.<br />
<br />
== Check the position control services ==<br />
The Position Control Service (pc) is used to drive the wheel a certain way or to turn the wheel a certain angle. There is one service per wheel.<br />
With the command pc.a,360,80 both wheels are comanded to: Turn the wheels an angle of 360 degrees with a maximum speed of 80%.<br />
<br />
Make a mark on a wheel to see how far it turns.<br />
<br />
pc.a, 360,80 Rotates both wheels forward by 360 degrees with 80% speed if everything is configured correctly.<br />
pc.a, -360,80 Rotates both wheels backwards by 360 degrees with 80% speed if everything is configured correctly.<br />
<br />
The Position Control can be stoped with the command<br />
pc.s<br />
<br />
<br />
If the wheel does not turn 360 degrees, the value CONF_ENCTICKSPERREVOLUTION in config.h appears to be wrong. For the original engines from the Ardumower shop, the value of 1060 is given.<br />
In addition, the constant CONF_RADUMFANG_CM is important for the calculation to be correct to drive a particular path in cm.<br />
<br />
Since the engine monitoring was switched off in the beginning in the config.h, it is now time to switch on again.<br />
Motor monitoring checks whether the encoders deliver values when the motors are turning, whether they are turning in the right direction, or whether the motor is actually turning when a PWM is applied.<br />
<br />
To enable motor monitoring in config.h, set the value CONF_DISABLE_MOTOR_STALL_CHECK to false.<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Recompile and upload. Then try again.<br />
No errors should be displayed.<br />
<br />
<br />
If everything works, the robot can be put on the wheels.<br />
<br />
Further tests can still be performed (note that the USB cable should be long enough, preferably use an extension);<br />
<br />
Drive a certain way in cm<br />
<br />
pc.cm,60,60,30,30 drives 60cm forward with the speed of 30%<br />
<br />
pc.cm,-60,-60,30,30 drives 60cm backwards with the speed of 30%<br />
<br />
<br />
<br />
Turning a certain angle. Prerequisite: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM and CONF_DISTANCE_BETWEEN_WHEELS_CM are configured correctly.<br />
<br />
turnto, 360,30 Turn the robot 360 degrees CW (clockwise)<br />
<br />
turnto, -360.30 Turn the robot 360 degrees CC (counter clockwise)<br />
<br />
If the robot does not turn 360 degrees, the constant CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h is probably wrong.<br />
<br />
==Mowmotor commissioning==<br />
The mowing motor does not use an encoder. It is operated with a PWM of 255. The PWM of 255 is not immediately given to the engine. It ramps up the PWM from 0 to 255.<br />
The same applies to the braking of the engine. It may happen that a motor fault is displayed when the engine is decelerating. This is because the inertia of the mowmotor disc tends to continue to rotate the motor, thus retroactively injecting a current into the motor driver that exceeds the limits such that the tri-state outputs of the driver go to high-impedance. If this happens, the error can be reset with the reset command.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
It may be that when stopping the motor a fault comes up. Reset this with the command reset.<br />
<br />
mot.curm //indicates the mowing motor current.<br />
<br />
<br />
If the PCB1.3 is used, the mower motor current is probably displayed incorrectly here. See: Adjusting the mower motor current in Tune Up<br />
This can be done later and is not so important for the first mowing operation.<br />
<br />
==Perimeter Commissioning==<br />
The Raindancer firmware works with two coils. This determines the angle at which the robot meets the perimeter. Accordingly, it is decided whether CC or CW is rotated. The perimeter signal must be received all the time while mowing. If the signal is not received for 2 seconds, the robot will stop and continue as soon as the signal is received again. The time that a non-receive is tolerated is set with the parameter CONF_PER_SIGNAL_LOST_TIME in the config.h. With this it is possib to bridge "Receiving holes" in the middle of the lawn. Disadvantage is, if the transmitter fails exactly when the robot is at the perimeter, it may be that the robot travels this set time outside the perimeter loop.<br />
<br />
Prerequisite for commissioning:<br />
The spools of the robot must be within the perimeter loop for commissioning.<br />
The Raindancer transmitter firmware must be installed on the transmitter.<br />
<br />
First check is if the signal is detected.<br />
<br />
You can see the calculated value of the individual coils as follows:<br />
per.resultl for left coil <br />
and <br />
per.resultr for right coil.<br />
The example below shows that the BAD has not received a valid signal.<br />
It is important here that no BAD is displayed. The received amplitude is behind mag :. The signal quality can be seen on the Peak Signal Noise Ratio psnr.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
End the output with h.<br />
<br />
Both coils should detect the signal, so do not indicate a BAD. Also not sporadicly!<br />
<br />
<br />
Next, the polarity of the signal must be configured. Enter:<br />
<br />
per.show. (switch off output with h)<br />
<br />
If the coil is inside the perimeter, the amplitude of the coil must be positive.<br />
<br />
The detected perimeter amplitudes are now shown.<br />
ML indicates the amplitude of the left coil, MR the amplitude of the right coil.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
However, one can see here that the magnetude on the left coil is negative.<br />
Inside the perimeter loop, this must be positive.<br />
<br />
This can be set in the config.h:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
After new compiling, the values should be positive.<br />
<br />
<br />
Attention, with per.resultl and per.resultr, the sign of the amplitude is displayed as actually received, regardless of the settings in CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE.<br />
It may be that per.resultl provides a positive amplitude and per.resultr a negative amplitude inside the perimeter. That's OK, since it depends on the connection of the coils. Conversion with CONF_LEFT_COIL_INVERSE / CONF_RIGHT_COIL_INVERSE takes place later in the software.<br />
It is important to configure CONF_LEFT_COIL_INVERSE and CONF_RIGHT_COIL_INVERSE so that per.show displays positive amplitudes within the perimeter.<br />
<br />
==Configure Bluetooth==<br />
<br />
If the module has already been configured with the original Ardumower software, can CONF_BT_SERIAL_SPEED=19200 be set.<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
(The perimeter outputs are extremely large.) It may be that the software faltered at this transfer rate when viewing perimeter data over BT at that baud rate.)<br />
This would be the configuration then done.<br />
<br />
<br />
Since there are sometimes problems with the configuration of BT modules, I suggest to reprogram a working BT module only if you have another working BT module in reserve.<br />
<br />
<br />
For the configuration of the BT the original Ardumower routine is used. However, the baud rate is set to 115200.<br />
Therefore, you can use the tips used for troubleshooting in the forum.<br />
<br />
<br />
Lets start:<br />
De-energize the PCB (also disconnect USB from the DUE). Press and hold button on BT module. Turn on the board.<br />
The BT module should now flash every 2 seconds.<br />
<br />
Release the button. Reconnect the USB to the DUE. The BT module should still be flashing every 2 seconds.<br />
<br />
Now try bt.show first, to see if the BT module is found:<br />
bt.show <br />
<br />
If found successfully put in the command:<br />
bt.set <br />
The BT module will now be configured.<br />
<br />
==Configure Arduino Central ==<br />
The software runs on an Android mobile phone or tablet.<br />
Arduino Central can be downloaded from the Play Store. Another software that works is Serial Bluetooth Terminal.<br />
<br />
In Arduino Central, the top right menu (three points) can be opened. Call Settings there.<br />
<br />
Then open the button layout Configuratin. Here you can set which buttons are displayed.<br />
Only the following should be selected:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Go back and open Serial Terminal Settings<br />
Set Terminal View Character Limit to 10000<br />
<br />
Go back and select Line Ending for Commands<br />
Select CR<br />
<br />
Go back and select Line Ending for Incoming Data<br />
Select NL<br />
<br />
Then first go out completely from the menu.<br />
<br />
First, the BT module must now be paired to work with the mobile phone.<br />
That means on the phone enable BT.<br />
Then go to the BT menu on the phone and look for new devices.<br />
There should then appear a new device. Select this device and pair.<br />
There is a password query which is 1234 or 0000<br />
Thereafter, the module is included in the device list<br />
<br />
Now in the menu of Arduino Central go to connect to device and click the BT of the mower.<br />
If everything was successful, BT connect should be displayed at the top right.<br />
<br />
At the command line, type H and Send. Then the help should be displayed.n.<br />
<br />
In Arduino Central commands can be stored under the menu item Standard Button Setup.<br />
Currently I have deposited the following commands with me:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
These commands can be customized as needed.<br />
<br />
== First test drive ==<br />
For safety reasons, switch off the mowmotor in config.h for the first test.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Then recompile and upload software.<br />
<br />
Attention, there are still no bumpers active! That the area inside the perimeter must be free.<br />
<br />
Disconnect the USB cable and connect to Arduino Central.<br />
<br />
<br />
Put the robot inside the perimeter loop.<br />
Check the perimeter signal again with show.per. Disable perimeter output with h or show.per output<br />
<br />
A enter for auto mode to start the mowing.<br />
<br />
It may take 5 seconds for something to happen. The robot first drives up the mowmotor. Since this one is turned off, it may look like it does not happen.<br />
<br />
M enter for manual mode to stop the robot.<br />
<br />
=TUNE UP =<br />
<br />
== Configure the bumpers on the bumper connectors ==<br />
The original Ardumower chassis does not provide a standard solution for bumpers. Since most users create their own solutions here, the firmware has some options to configure the bumper service for their own needs.<br />
<br />
To enable the bumper, the following line must be configured in config.h:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
To test bumpers, you can use the bumper.show command. The bumper service then plays its activity on the console or mobile phone, depending on where that command was sent from.<br />
bumper.show <br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor. This means, the input is high by default as long as the pin is not connected to GND by a switch for example.<br />
<br />
The bumper service can be configured with following parameters in config.h:<br />
<br />
<br />
Using the left or/and right bumper<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Determine if the bumper is aktive if the pin is connected to GND:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
If one uses a left and a right bumper, there is still the possibility to configure that the direction of rotation is determined by the activated bumper after driving back. That means, that when the left bumper is pressed, the robot then turns right after driving back.<br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
The bumper pins are configured by default as inputs with pullup resistor in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
This means the input is high by default if the pin is not pulled to GND.<br />
<br />
<br />
''If you want to switch off the pull-up resistors, the lines must be changed as follows''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
The charge ervice provides the BHT with the charge voltage and the charge current. It contains functions for switching the charger relay on / off.<br />
<br />
<br />
Annotation:<br />
If the Mower is switched off (battery not connected) and then a charging voltage is connected to P42 Charger,<br />
the board is directly supplied with voltage via D73. The problem is that the capacitors on the board have no voltage and supply a short circuit when connected. Then a 1.6A fuse will break through in EF1.<br />
Therefore, EF1 should be 5A.<br />
I've removed the D73 from my board, because I think it's only reasonable if the battery is so empty that the board and Relay no longer works with the battery. If this really <br />
happens, I will charge the battery directly with the charger. This should be happen only in case of an error and should not be the rule (but I would not persuade anyone to do this too).<br />
Furthermore, the D73 has a different potential on the back, as the diodes are soldered behind this. Since it makes sense to separate them with hot glue, not that they come together.<br />
<br />
[[The following describes how to load the robot.]]<br />
<br />
'''Independent driving in the charging station'''<br />
<br />
When the robot moves into the charging station, the charging relay is switched off. At this time, only the voltage of the charging station is at the contacts.<br />
If the robot has detected this, it stops, waits two seconds and checks the charging voltage again. If this is OK, it moves 3cm forward, 3cm backwards and again 2cm forward.<br />
This serves to optimize the connection to the charging contacts (which are currently designed as sliding contacts). Then the relay is switched on and the charging voltage checked again.<br />
(This behavior can easily be reprogrammed in the BHT.) The relay remains energized and thus the battery is connected to the charger until the robot is commanded to go to an area or the robot is switched to manual mode or switched to auto mode.<br />
<br />
'''Use without charging station'''<br />
<br />
To load the robot it should be in manual mode (enter command M). Then you can use charge.relay,1 to switch on the relay and with charge.relay,0 to switch off the relay. The relay automatically turns off when the Auto mode is activated. '''The relay only switches on if the charging voltage is applied to the charging contacts!'''.<br />
Another possibility is to connect the charging contacts when switched off and then turn on the robot. The robot then goes into auto mode and turns on the Behavior Charging Station. He now thinks he is in the charging station. <br />
<br />
'''Put in the charging station'''<br />
<br />
Here, put the robot in the switched off state in the charging station, so that the charging contacts have contact. Then turn it on. The robot then enters the charging mode in the Behavior Charging Station. He now thinks he is in the charging station, turns on the relay and charges.<br />
<br />
<br />
To enable the charging service, set the config.h CONF_DISABLE_CHARGE_SERVICE to false and re-install the software.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manual testing:]] <br />
<br />
Enter the command:<br />
charge.show <br />
This continuously displays the voltages and currents. Currently everything should be displayed with 0.<br />
<br />
Connect charger to P42 or charging contacts.<br />
<br />
Now you should see the Charge Voltage (CV)..<br />
<br />
Enable relay:<br />
charge.relay,1<br />
<br />
Now a current flows from the charger to the battery and a charge current is displayed (CC).<br />
<br />
Disable relay:<br />
charge.relay,0 <br />
<br />
<br />
[[Testing in the off state via the console:]]<br />
<br />
Turn on the robot and connect USB. Wait until software has started up.<br />
Connect charging contacts. <br />
Open the serial console. The DUE restarts. The relay should be energized and the console output at boot should show "Charging station detected".<br />
The robot has now switched to the Chargingbehaviour.<br />
<br />
Enter M to return to manual mode and switch off the relay.<br />
<br />
==Watchdog==<br />
The watchdog is solely for safety.<br />
If the software hangs, the watchdog should prevent the robot from running unchecked.<br />
The watchdog is hardware implemented in the DUE. It is activated in the config.h with:<br />
#define CONF_ENABLEWATCHDOG true<br />
<br />
<br />
Each time the loop is traversed, the watchdog will be reseted with the function call watchdogReset ();.<br />
If watchdogReset (); is not called within 3 seconds (because the software hangs somewhere), the DUE is restarted, stopped the engines and the software goes into manual mode.<br />
<br />
Annotation:<br />
Since the variables of the firmware are reinitialized during the reboot, it is difficult to find out what the cause of the error is.<br />
The Mower simply stops, and one wonders when opening the BT connection, that everything is fine and no error is issued - except that the software is in manual mode.<br />
<br />
== Undervoltage Shutdown ==<br />
The undervoltage shutdown is used to prevent the battery from falling below a certain voltage and then deeply discharged. The implementation of the undervoltage shutdown is implemented in the battery service.<br />
Prerequisite is, that the jumper 8 UV shutdown on PCB 1.3 is set to Auto. If you then put voltage on the board, this gets no electricity first. Therefore, when switching on the voltage, the UV shutdown must be bridged with the P20 button. Then the PCB1.3 gets voltage. This button should be held for 4 seconds. Then the software takes control of the UV shutdown. The P20 button must then be open again, otherwise the software can not switch off the voltage.<br />
<br />
<br />
In config.h the threshold is set at which the voltage is switched off<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
If the battery voltage falls below this voltage for one minute, the voltage to PCB1.3 and the motors will be cut off.<br />
The entire PCB1.3 is then dark.<br />
<br />
If you want to bridge the undervoltage cut-off, you can set jumper 8 to permanent-on or bypass P20. I have an on / off switch connected to the P20, so that I can bridge this for testing purposes. The jumper 8 is still on auto.<br />
<br />
==I2C Bus==<br />
The I2C bus can be scanned with the command i2c.scan. All found addresses will be displayed.<br />
<br />
i2c.scan<br />
<br />
The addresses of the RTC module and the EEPROM can be adjusted in the hardware.cpp. Currently the following default addresses are configured:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
The RTC module is currently not used. It is intended to use this later for a time mowing start.<br />
However, the RTC module can already be programmed and tested.<br />
<br />
The RTC module is activated with the following line in the config.h:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
The EEPROM is used on the RTC. Currently it is used to store statistics. The following statistics are stored: total mowing time, total distance traveled, total number of rotations, number of loading operations.<br />
<br />
The use of the EEPROM is switched on with the following line in the config.h:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
The following commands are available for the EEPROM:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
To test the EEPROM e.g. enter the following command:<br />
eep.set.f,10,7.3<br />
This writes the float value 7.3 to the addresses 10, 11, 12, 13 in the EEPROM.<br />
<br />
With the command <br />
eep.f,10<br />
the value can then be read out again.<br />
<br />
The command eep.erase deletes the first 3 pages of the EEPROM. The other pages are currently not deleted because they are not used.<br />
eep.erase<br />
<br />
It makes sense to erase the EEPROM after the enable the service so that the memory cells are initialized.<br />
<br />
== Slow down the speed at the perimeter ==<br />
The Mower drives at a speed of 1200m / s. In order to make the deceleration a bit gentler when driving over the perimeter, the robot reduces the speed just before the perimeter (about 20 cm). <br />
<br />
The following constants in the config.h affect recognition near the perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
To determine if the robot is close to the perimeter, the amplitude of the left and right coils are evaluated. For this purpose, the firmware determines the current maximum amplitude over the entire travel time of the Mower. Now, when the left coil reaches an amplitude of 80% (CONF_NEAR_PER_UPPER_THRESHOLD) or higher of the maximum value and the right coil reaches above 70% (CONF_NEAR_PER_LOWER_THRESHOLD) or higher of the maximum value, it is assumed that the robot is close to the perimeter. The same applies if the right coil reaches 80% and the left 70%.<br />
<br />
These values depend on the kind of coil used and on the signal strength of the transmitter and therefore may need to be readjusted.<br />
<br />
To adjust this, enter the command per.show while the Mower is driving.<br />
per.show <br />
If the mower then runs over the perimeter wire enter the same command or press h. Then scroll back in the display and look at the values.<br />
<br />
Example:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
The values magMedL%: 73 magMedR%: 87 indicate here the measured percentage of the coils 20cm before the perimeter wire. Use this percentage as starting point to set CONF_NEAR_PER_UPPER_THRESHOLD and CONF_NEAR_PER_LOWER_THRESHOLD. Several tests should be carried out for the determination. Better to slow down a little earlier than to slow down too late. The difference between UPPER and LOWER has been introduced because the coils do not have always the same value, e.g. when the Mower is running obliquely or almost parallel to the perimeter. <br />
<br />
It may be that magMedL% and magMedR% show more than 100%. This is based on the type of magMax determination and is OK.<br />
<br />
The calculation is stored in the function '' 'bool TPerimeterThread :: isNearPerimeter ()' '' in the file perimeter.cpp.<br />
<br />
== Set mower motor current ==<br />
It should be noted that the outputs of the mowing motor driver on PCB1.3 have been interconnected.<br />
<br />
With a PWM of 255 at the mower motor almost no current is measured on my board. I have then remeasured the value with a multimeter. I measure at M2 FB at full speed and free-wheel only 0.04V. Correct value would be about 0.22V because the engine pulls here 0.41A. On M1 M1 I measure a voltage of 0.007V. It seems that the current measurement is no longer correct due to the parallel connection. One might think that this should be halved. But it is not like that.<br />
<br />
<br />
An interconnection of the two MC33926 is not recommended by the manufacturer and seems to provide an incorrect current measurement.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Quote:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
<br />
I have then disconnected from the Mowmotor driver pins M1 OUT1 and M1 OUT2 (bent and guided next to the socket connector, so that they have no contact). Now the current measurement works properly, but under 1A this is not really accurate. Only from 1A the value is reliable.<br />
<br />
Forum Posts:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
If M1 OUT1 and M1 OUT2 are not disconnected, the measured and displayed current too low.<br />
Therefore, the scale value for the correct current measurement must be adjusted in the setup function of the class TMowMotorSensor in the file mowmotorSensor.h.<br />
The scale factor should be set at currents around 1A or more. Therefore he mower disc must be loaded with resitance when measuring the current with the multimeter.<br />
<br />
If M1 OUT1 and M1 OUT2 are disconnected, the factor whih is set by default and find out by measuring is probably reasonably correct. However, this can only be checked by measuring current levels of 1A.<br />
<br />
The measured current and wattage are displayed with the command:<br />
mot.curm<br />
<br />
== Slow down when mower engine is loaded ==<br />
When the mower motor is loaded, the mower slows down.<br />
<br />
From which wattage of the mower motor the mower is slowed down, can be configured in the config.h with the parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
If the mower needs more than 30W, the speed will slow down.<br />
<br />
The current watts number when mowing can be displayed with the command:<br />
mot.curm <br />
Thereafter, the value can be set at its discretion.<br />
<br />
Attention, the motor drivers deliver an accurate current measurement only from 1A on (according to data sheet 0.5A).<br />
That Values where the current is displayed under 1A are inaccurate and should not be used.<br />
The accuracy is according to data sheet at a current of over 0.5A + -20%.<br />
<br />
The speed setting code is in the class class TCruisePerimeterNear: public Node in the bCruise.h file.<br />
<br />
Furthermore, it must be taken into account that the outputs of the mower motor driver have been interconnected. This is not recommended by the manufacturer and provides incorrect current measurement.<br />
<br />
==Archimedean Apirale==<br />
If the mower motor is loaded, an Archimedean spiral can be activated. It starts with a small curve at the start, so that the inner wheel turns. Therefore, a small tuft of grass will remain in the middle of the spiral.<br />
<br />
The spiral is activated in the config.h with the following line:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
The parameters listed below can be customized as desired. If the spiral is turned too often, the robot will not get off the ground and will only work one area of the lawn.<br />
<br />
The following parameters in the config.h affect the activation of the spiral:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
The implementation of the spiral activation is in the file: bCruise.h Class: class TCruisePerimeterNear: public Node<br />
<br />
The code for activation is as follows:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
There are two independent conditions for activating a spiral travel (a) and (b).<br />
<br />
(b) A spiral is activated when bb.mowMotorSensor.checkIfUnderLoad () returns true and no spiral has been taken for the last 3 minutes. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by following constant:<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
If the mower needs more power than defined by CONF_MOW_MOT_UNDER_LOAD, the function bb.mowMotorSensor.checkIfUnderLoad () returns true otherwise false.<br />
CONF_MOW_MOT_UNDER_LOAD also affects "slow down when mower engine is loaded" as described above.<br />
<br />
(a) A spiral is activated when bb.mowMotorSensor.motorUnderHeavyLoad () returns true and no spiral has been taken for the last 60 seconds. The calculation in bb.mowMotorSensor.checkIfUnderLoad () is affected by the constants:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
To determine if the engine is under heavy load, a hysteresis is used. As soon as the mower engine wattage goes above CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON, bb.mowMotorSensor.checkIfUnderHeavyLoad () returns true. But only when the wattage goes below CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF will false be returned.<br />
<br />
The functions checkIfUnderHeavyLoad () and checkIfUnderLoad () are in the file: mowmotorSensor.h class: class TMowMotorSensor: public thread defined.<br />
<br />
The implementation of the spiral itself is in the file: bCruise.h Class: class TCruiseSpiral: public Node<br />
<br />
The following values influence the driving of the spiral:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Note: The BHT indicates that the spiral in class TCruiseMowMotHeavyLoad is started. This is not the case as the implementation is very simple. The class TCruiseMowMotHeavyLoad does not exist. The function was implemented in the class TCruisePerimeterNear.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Here, the perimeter tracking algorithm is explained, with the aim of providing enough information to be optimized by the user on its chassis. The choice fell on this algorithm, since it is independent of the perimeter amplitude. Furthermore, the algorithm is extremely stable and is to be diverted from its intention to follow the perimeter. [https://www.youtube.com/watch?v=RdufyzkYSPU '' 'Video Example' '']<br />
<br />
The perimeter tracking algorithm uses a one bounce algorithm. The algorithm move off counterclockwise on the perimeter. The right outer coil bounce always against the perimeter from the outside. When it hits the perimeter, the coil is first repelled by the perimeter. Thereafter, the coil moves in an arc towards the perimeter. [https://www.youtube.com/watch?v=Y3wxURV0qtw '' 'Video Example' '']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
The algorithm is in the file: bGotoAreaX.h class: TlineFollow implemented.<br />
The following diagram shows the "if" queries in a different chronological order for a better explanation than they actually are in the program code. Therefore, do not be confused when looking at the program code.<br />
<br />
Procedure:<br />
The right coil is always outside the perimeter.<br />
If this exceeds the perimeter inwards, an aggressive rotation is first executed clockwise with:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Should the coil not be outside after 1 second, the rotation becomes more aggressive:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
If the coil is not outside after 1.5 seconds, the mower will turn<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
When the coil is now turned out, the robot moves a shallow counter clockwise curve until it reaches the perimeter.<br />
For the calculation of the curve, an integral is used, which can be controlled by the factor Ki.<br />
(Note: The integral is set to 0 as soon as the coil crosses the perimeter.)<br />
<br />
integral = integral + (Ki*error); // the value error is a constant and has the value -1 if the coil is outside the perimeter.<br />
double Output = integral;<br />
<br />
The move of the curve is then carried out as follows: As the integral increases, the curve becomes smaller as the integral becomes larger.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // note: output is negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
If the perimeter is not exceeded after 1 second, the curve is driven more aggressively;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
If after 1.5 seconds the perimeter was not exceeded, the curve is driven even more aggressive:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
If after 2 seconds the perimeter has not been exceeded, the following is rotated:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
If the left coil is outside the perimeter, immediately counter clockwise is turned:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
To set the algorithm, the first thing you should try to do is drive straight. Here is the first turn out to configure and Ki for the curve to drive in.<br />
<br />
Testing the algorithm:<br />
Place the robot on the perimeter so that the right coil is on the outside and the left coil on the inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
The command<br />
M<br />
stops the test.<br />
<br />
With the command<br />
set.lfki, 1.1<br />
the Ki value can be set during testing. If satisfactorily determined, the value must be assigned in the TlineFollow class in the constructor.<br />
<br />
When the drive wheels are rear, the distance to the coils is greater and the coils can be located off center. The original Ardumower chassis has front drive wheels. Here, the right coil must be placed close to the center, otherwise the rotation is too asymmetrical. Due to the short distance, the bounce interval of 1 sec is probably to be shortened, so that on a straight line probably all 0.3sec must be bounced. (Currently not tested)<br />
<br />
== Fast return ==<br />
On the way back to the charging station, it may happen that the Mower drives at one point onto the perimeter so that it has to drive the entire perimeter wire to the charging station. To shorten this way, there is the fast return.<br />
The user has to lay the perimeter cable so that it results in a square. This quadrilateral is then recognized by the robot during perimeter tracking. When he recognizes the square, he turns 90 degrees from the perimeter into the interior, and moves to the other side of the lawn. When he discovers the perimeter cable, he picks up the perimeter tracking again.<br />
<br />
To enable the fast return you have to set following option in config.h.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
For the square, the following dimension has been found to be favorable. However, it depends on the dimensions of the Mower. The Mower should come while tracking in the turning mode. Turn at the first left curve. Then turn at the next right curve. Then drive left curve. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
<br />
The square can be laid in two ways. Once with corners and once with flattened corners. The flattened corners are there for the mower to better recognize at the corner in which direction it should turn away from the perimeter when it is almost parallel to the perimeter. As a result, the perimeter nearest coil is the first outside and it turns away from the perimeter rather than toward the perimeter. This is necessary if there is a bed behind the perimeter into which the mower could turn.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Example, how I lay down my squares<br />
</gallery><br />
<br />
<br />
The detection depends on the position of the coils and the distance between the coils and the drive wheels.<br />
<br />
The implemetation is in the file: bPerimeterTracking.h Class: class TfindTriangle: public Node<br />
<br />
Detection is based on the rotated angle. It was implemented with a state machine.<br />
<br />
The procedure of the statmachine and the calculated angles can be displayed with the command:<br />
bht.tri <br />
<br />
The corresponding angles and maximum distances must then be adapted in the code in class: class TfindTriangle.<br />
Below Ishow slightly thinned class to get a better overview. The lines errorHandler.setInfoNoLog (..) are the output if the command bht.tri has been activated. These were listed here to better interpret the issue.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
The driven angle is determined every 500ms before the case statement.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Query the States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
In case 0, a left turn is searched. A negative angle means a left curve/turn. If the angle is e.g. <-25 degrees, a curve was found and it will branched into case 1. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1, it is constantly checked whether a certain distance has been exceeded after the left turn. In the example 55cm. If so, that is too far and it jumps back into the case 0, since it can not be that the first way is so long. If an angle> 50 has been found within the distance of 55cm, the case 2 is jumped. A positive angle means a right turn.<br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2, the distance traveled after the right angle is checked first again. As long as the distance of 50 cm has not been exceeded, a left turn is checked. If the angle is <-25 degrees, a curve was detected and jumped into state 3. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 returns BH_SUCCESS to the BHT and the mower drives to the other side of the lawn.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testing the Algorithm: Place the robot on the perimeter so that the left coil is on the outside and the right coil is inside. Start the perimeter tracking with the command.<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
<br />
<br />
Start the output of the quadrilateral detection with the command. <br />
bht.tri <br />
(tri stands for triangle, since previously a triangle was used for detection)<br />
<br />
== Mowing zones between adjacent surfaces ==<br />
Mowing zones can be set up between adjacent surfaces that have a direct connection. For this, the perimeter cable between the surfaces is laid at a distance of about 13cm. A gap of about 30cm or less is left to the opposite perimeter cable. This reduces the likelihood that the robot will move to the other area.<br />
<br />
See image:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(In the picture above, it is not normally necessary to set up mowing zones, as the robot covers relatively well all areas of the lawn by the algorithm.)''<br />
<br />
The distance of the area delineation cable to the opposite perimeter cable (here 30cm distance) can be optimized by tests. The distance depends on the functionality of the perimeter tracking. Firstly, the position of the left coil when tracking the overlying cable, as well as the tracking of the area delineation cable itself.<br />
<br />
In config.h the constant CONF_USE_ZONE_RECOGNITION should be set to true.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Since the robot travels with the coils about 20 cm over the cable by default, it may be that it stops with the coils within the next range.<br />
If CONF_USE_ZONE_RECOGNITION is false, the robot would simply continue driving as it may have crossed a corner.<br />
If CONF_USE_ZONE_RECOGNITION is true, it will be checked after crossing if both coils are inside the perimeter again. If so, at least a distance of (-CONF_PERIMETER_DRIVE_BACK_CM-10) is returned. So 10cm more than usual CONF_PERIMETER_DRIVE_BACK_CM would go back.<br />
<br />
Approaching an area from the charging station is done with the command:<br />
area,x // where x is the path to be traveled in m.<br />
If the specified distance x has been covered at the perimeter, the Mower starts mowing.<br />
<br />
The distance traveled on the perimeter can be displayed or measured with the command.<br />
show.distance<br />
<br />
<br />
Attention: It is important to remember exactly where the mower zone cables are located in case the grass is scarred..<br />
<br />
== Laying the Perimeter Cable at Corners ==<br />
The Mower determines in which direction he turns on the perimter on the basis of the coil that was pulled out first. Therefore it is important not to lay the corners at 90 degrees.<br />
For example, if the Mower, with the right spool, moves close parallel to the perimeter and then drives out at the corner, the right spool should also be the first to leave the perimeter.<br />
<br />
The following pictures show three examples of how corners should be moved..<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperature Sensor==<br />
The temperature sensors DHT11 / DHT21 / DHT22 / AM2301 are supported. Currently only the sensor DHT22 was tested.<br />
The temperature sensor is connected to the designated port of the PCB1.3.<br />
<br />
In config.h the used temperature sensor must be configured:<br />
#define DHTTYPE DHT22 <br />
<br />
To enable the service, the following line must be configured:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
The sensor is read out with the following command:<br />
temp.show<br />
In manual mode, the sensor is read out directly. Temperature, humidity and the last temperature stored in the service are displayed.<br />
In auto mode, only the temperature stored in the service is displayed. The temperature is updated when the mower drives over the perimeter wire and comes to a stop and time has passed at least 20 seconds since the last measurement.<br />
<br />
The DHT service turns off the power of the PCB1.3 when a temperature of 50 degrees has been measured twice:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
When the shutdown service is activated, it shuts off the power via the undervoltage protection.<br />
If a Raspberry PI is connected to the USB port, <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
can be set.<br />
Then the software waits 50 seconds for shutdown.<br />
Every second, $PwrOff and a countdown are sent to the PI so that it can shut down.<br />
<br />
With the command:<br />
poweroff<br />
the shutdown can be activated via the user interface or from the PI.<br />
<br />
The shutdown service is also used by the battery service and the temperature service to shut down.<br />
Thus, the PI is informed that it should shut down if the battery voltage is too low or the temperature too high.<br />
<br />
==GPS Service==<br />
The GPS service receives the data from the GPS module.<br />
<br />
There are two ways to process this data. Both options can be used in parallel.<br />
a) The received GPS data will be forwarded to the Raindancer Controlcenter.<br />
b) The received GPS data are evaluated in the Raindancer firmware. You can then define an area on the lawn.<br />
If the mower is in this area, it is assumed that the mower is inside the perimeter wire. So it is possible to bridge a weak perimeter signal on larger areas.<br />
<br />
The GPS module is connected to the dedicated connector on PCB1.3. The GPS module periodically sends data to PCB1.3.<br />
If no data is received, please read the following article. It may be that RX3 and TX3 on the PCB1.3 were wired incorrectly.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Send to the Raindancer Controlcenter===<br />
To enable the GPS service, the following must be configured::<br />
#define CONF_DISABLE_GPS false<br />
<br />
For the first commissioning you can set the following parameters:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
The parameter #define CONF_GPS_PASS_THROUGH tells the firmware that all received GPS data should be sent to the control center.<br />
<br />
<br />
In order to get this data displayed on the console, the following command must be executed:<br />
set.cco, 1<br />
Now you can see all the data sent to the control center. Including the GPS records.<br />
<br />
With the following command you stop the output:<br />
set.cco,0<br />
<br />
<br />
<br />
By default, the GPS module sends multiple records in a 1 second interval. These records are not all needed and generate an overhead.<br />
Only the record: $GPRMC for NEO-6M and $GNRMC for NEO-M8N are needed.<br />
Therefore, there is the possibility to configure the module when starting the Raindancer firmware so that it sends only the required record and this only in a 3 second cycle.<br />
For this the following parameter is set:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Thus the array const char UBLOX_INIT [] (in config.h) is sent to the GPS module during startup. To activate or deactivate you have to comment in or comment out individual lines.<br />
<br />
<br />
=== Enable internal calculation ===<br />
Again #define CONF_INIT_GPS_WITH_UBLOX should be true.<br />
To activate the internal calculation CONF_DEACTIVATE_GPS_CALCULATION must be set.<br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
For the NEO-6M module, the record: $GPRMC is used. The NEO-M8N uses the record $GNRMC.<br />
Therefore, the following lines must be commented in or out depending on the module used:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
With<br />
gps.show<br />
you can display the calculated values.<br />
<br />
If you have included the "GxGGA on" data set in UBLOX_INIT [], then Quality, Satellites and Altitude will also be displayed. These are not used anymore for other things.<br />
<br />
<br />
It is possible to configure a GPS area in which the Mower assumes he is in the perimeter if the perimeter signal is too weak for detection.<br />
<br />
The area is specified as a polygon.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Each column belongs to a polygon point. You can at https://www.google.com/maps enter a point in the search: 54.08728,10.448400. Then you can see where this coordinate is. So you can see point by point how the polygon is constructed.<br />
It is important that the number of columns is defined correctly with CONF_NUMBER_OF_POLYGON_POINTS. You can enter 3 to N coordinate points. However, I suggest you use no more than 8 points to make the calculation time as low as possible<br />
<br />
To find the points, you can set the robot to the appropriate point and enter gps.show. Then, e.g. the following is displayed:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
The point can then be taken from the line! 03,$GPRMC,lat:53.08744800,N lon:9.44867700,E. Here for Latitude = 54.087448 and Longitude = 10.448677.<br />
<br />
<br />
The area recognition is switched on with:<br />
#define CONF_USE_GPS_POLYGON true<br />
<br />
<br />
It should be noted that the GPS signal has a tolerance of +-10m. That you should stay far enough away from the perimeter. Because that does sometimes not work, the parameter<br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
was introduced. This means that if the amplitude of the perimeter exceeds this value, the perimeter signal will be used in any case and will not be overwritten by the GPS signal, even if the mower is in the GPS range.<br />
The value 300 must be set according to your own requirements..<br />
<br />
[[File:warning.png]]'''Safety Note: If the perimeter signal fails and the GPS range exceeds the perimeter, the mower will leave the perimeter area'''<br />
<br />
=Perimeter Sender=<br />
The original Ardumower transmitter hardware is used. The software has been changed slightly. A 128 bit signal is sent.<br />
The following perimeter signal is sent:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
The LEDs have the following function (from left to right):<br />
*1. 12V available<br />
*2. 5V available<br />
*3. Green when the interrupt which produces the signal is running (red LED not available because of wrong pin at Nano). Off when charging.<br />
*4. Green when a current flows through the perimeter, red when no current is flowing (perimeter interrupted) or very little current because of high protective resistor. Off when charging.<br />
*5. Yellow the robot is charging. Perimeter signal is switched off. LED 2 and 4 off.<br />
<br />
When power on, all leds will be tested.<br />
<br />
Attention: LEDs 3 and 4 are Duo LEDs. These LEDs have two colors. With LED 3. the red LED is not addressable, because on the Nano the wrong pin was hardware-technically connected. Furthermore, the LEDs may have been soldered the wrong way round. Then one wonders, for example, that LED 4 is red even though everything is OK and a current flows. Or just LED 3. shows red, although I have written green here.<br />
<br />
'''If the transmitter is on and the robot does not return to the charging station after twelve hours, the transmitter will turn off the signal.''' Then either reboot the transmitter or load the robot into the charging station.<br />
<br />
=Charging Station =<br />
The charging stations are approached counterclockwise.<br />
<br />
If no charging station is used, <br />
CONF_DISABLE_CHARGINGSTATION = true<br />
should be set. Then the Mower drives at low battery voltage to the perimeter and stops.<br />
<br />
==Head charging station==<br />
<br />
If a head charging station is used, make sure that the contacts can go back at least 3 cm when the Mower drives against it. It would be better 4 cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a head charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 0<br />
The Mower then drives 1m backwards, turns 90 degrees and drives 50cm forward. Then turn again a random angle and starts to mow. This process runs without bumper protection. Therefore, make sure that this area is free of obstacles.<br />
<br />
The distances can be configured with the following parameters:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
When the Mower has detected the charging contacts, it will travel 3cm back and 3cm forward.<br />
Then the charge relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be issued.<br />
<br />
==Through Charging Station==<br />
If a through charging station is used, make sure that the contacts can grind at least 10cm. Furthermore, it should be noted that the contact pressure of the contact is sufficient.<br />
<br />
In order to use a through charging station, the following must be configured in config.h:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
With the command<br />
go home<br />
the mower is instructed to search the perimeter wire and drive to the charging station.<br />
<br />
For testing, the Mower can be placed on the perimeter wire, 2m in front of the charging station. Then enter<br />
tpt<br />
The Mower then drives to the charging station.<br />
<br />
To leave the charging station enter<br />
area, 10<br />
The Mower then travels 10m along the perimeter wire and then starts mowing. 10m can be exchanged against any distance.<br />
<br />
<br />
When the Mower has detected the charging contacts, it will move forward 4cm, back 3cm and forward 3cm. This is to make the contacts to grind a little for better contact.<br />
Then the charger relay is turned on. After 10 seconds, it is checked whether a charging current is flowing. If not, docking will be attempted a second time. If this does not work, an error will be output.<br />
<br />
=Troubleshooting=<br />
== Mower stops ==<br />
[[Problem:]]<br />
Mower stopped, cause was probably the transmitter. On the transmitter just lights still the two left LEDs. Transmitter turned and on again, 4 LEDs back to green and then it works again.<br />
<br />
[[Solution:]]<br />
The third green light from the left indicates whether the transmitter Interrupt is running in the Nano.<br />
<br />
Possibility A)<br />
The transmitter is on for more than 12 hours without the robot returning to the station. Then the transmitter turns off the perimeter signal.<br />
<br />
Possibility b)<br />
Since this was not on, the nano seems to have hung up. If that happens again, I would swap the China Nano for an original Arduino Nano. Since the software has been running for me for a year, I do not assume that the software is the cause. I had used cheap nanos before. They were not really frequency stable with me, which is necessary for the transmitter however. Now I have an original in it.<br />
<br />
==I got the message: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Suggested solution:]]<br />
In the Arduino Central Settings "Read Command -> Enable Read Command" is activated<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Rolandhttps://wiki.ardumower.de/index.php?title=Raindancer_Firmware_(Deutsch)&diff=6244Raindancer Firmware (Deutsch)2018-07-29T16:34:36Z<p>Roland: /* Durchgangsladestation */</p>
<hr />
<div>Achtung! Die Software ist noch im Wandel und kann jederzeit geändert/erweitert werden.<br />
<br />
=Download=<br />
[https://github.com/Ardumower/Raindancer Github Download]<br />
<br />
(Auf Github mit dem grünen Button das Zip-File herunterladen)<br />
<br />
Die Raindancer Firmware befindet sich im Verzeichnis code\Raindancer<br />
Die Sender Firmware befindet sich im Verzeichnis code\sender<br />
<br />
=Überblick=<br />
Die Raindancer Firmware beruht auf dem Code des Nucleomowers welche mit dem Entwicklungsboard STM32 Nuleo 411RE im Jahr 2016/2017 realisiert wurde. Die Firmware wurde dann im Jahr 2017/2018 auf das Ardumower PCB 1.3 konvertiert. Sie verfolgt das Ziel, mit möglichst geringem Hardwareaufwand ein stabiles System zu bekommen, welches das ganze Jahr arbeitet und ein gutes Mähergebnis mit dem Chaosprinzip liefert. <br />
<br />
Die Firmware hat folgenden '''Workflow''':<br />
Der Mower steht in der Ladestation. Der Mower fährt von der Ladestation eine vorgegebene Strecke am Perimeter entlang zu einem Bereich und fängt dann an nach dem Chaosprinzip zu mähen. Die Mähzeit beträgt mit den original Ardumowerkomponenten ca. 130min-150min. Nachdem die Batteriespannung auf 23,7V heruntergegangen ist, sucht der Roboter das Perimeterkabel und fährt dieses bis zur Ladestation entlang. In der Ladestation angekommen, wird die Batterie geladen. Der nächste Mähvorgang wird über das Mobile Phone erneut mit einem Bereichsbefehl gestartet. (Der Roboter kann auch ohne Ladestation betrieben werden.)<br />
<br />
Die Firmware wurde entwickelt für Roboter mit dem Antriebsmotoren hinten, kann aber auch für das original Ardumower Chassis verwendet werden. Optimierungen für das original Ardumower Chassis erfolgen zu einem späteren Zeitpunkt.<br />
Der Mower dreht sich auf dem Perimeter. Wenn eine Spule über das Perimeterkabel gefahren ist, fährt der Roboter noch ca. 20cm weiter. Dann werden beide Spulen, in die Schleife gedreht und ab da an wird dann mit einem Zufallswinkel weitergedreht. Da das original Ardumower Chassis einen kurzen Abstand zwischen Spulen und Rädern hat, gibt es hier folgenden Workaround: In der config.h kann eingestellt werden, dass der Mower weiter zurückfährt, dann einen festen Winkel dreht (Drehung auf dem Perimeter simuliert) und nach dem Drehen des festen Winkels wird der Zufallswinkel gedreht. <br />
<br />
Intern in der Firmware werden Strecken nach cm Angaben gefahren. D.h., es werden Encoder benötigt.<br />
<br />
Für die '''Perimetererkennung''' wird ein 128Bit Signal verwendet. Daher muss die Raindancer Sendersoftware auf den Sender aufgespielt werden. Es werden 2 Perimeterempfänger benötigt. Beim Annähern an das Perimeterkabel wird der Roboter langsamer. <br />
Erkennt der Roboter das Signal für 2 Sekunden nicht, bleibt er stehen und schaltet die Motoren aus. Erkennt er es wieder, fährt er weiter.<br />
<br />
Die Firmware unterstützt in der aktuellen Version eine durchfahrende Ladestation (unterstützen einer einseitig befahrbaren Ladestation folgt zu einem späteren Zeitpunkt). Das Anfahren der Ladestation kann in der Software ausgeschaltet werden. Dann bleibt der Roboter am Perimeter stehen, wenn die Batteriespannung unter 23,7V fällt. Zum Laden kann der Roboter dann ausgeschaltet werden, an das Ladekabel angeschlossen werden und wieder eingeschaltet werden. Der Roboter geht dann in den Lademodus. Fällt die Spannung unter 21,7V löst die Unterspannungsabschaltung aus falls diese nicht überbrückt wird.<br />
<br />
Mit den original Motoren und Rädern fährt der Roboter mit einer Geschwindigkeit von ca. 1200m/h. <br />
Um ein vernünftiges Schnittbild zu erlangen, muss der Roboter bei einer 1000m² Fläche ca. 6-9h pro Tag mähen (meine Erfahrung). Hängt natürlich auch von der Art und Verwinkelung der Fläche ab.<br />
Für die Beschleunigung und das Abbremsen wird der Simple Trajection Planer vom Linux CNC Projekt verwendet. Dieser ermöglicht ein sehr sanftes Anfahren und Abbremsen.<br />
<br />
Falls ein original Bumperduino, Bumper mit Schaltern, Halleffekt Sensoren,... verwendet werden, können diese wie bisher an die Bumper Pins angeschlossen werden. <br />
<br />
Optimiert wurde die Firmware für '''nicht mit dem Perimeterdraht eingezäunten Hindernissen''' auf dem Rasen. Anstatt mit voller Geschwindigkeit gegen das Hindernis zu fahren, wird ab einem bestimmten Abstand die Geschwindigkeit verringert und seicht gegen das Hindernis gefahren. Voraussetzung sind dafür Sonarsensoren. Diese Funktion ist optional.<br />
Dazu unterstützt der Roboter einen selbstgebauten Bumperduino mit zwei MaxSonar Sonarsenoren und einem MPX5010DP FREESCALE Drucksensor für einen Druckwellenschlauch. <br />
https://github.com/kwrtz/Raindancer/blob/master/DipTrace/DistanceBumperSensor/DistanceBumperSensor.pdf <br />
Die Auswertung übernimmt ein Arduino Nano, welcher am PinUserSwitch2/3 des PCB1.3 angeschlossen ist. Bei Erkennen eines Hindernisses mit den Sonarsenoren, wird der Roboter langsamer und bumped seicht gegen das Hindernis wo dann der Bumper oder Bumperduino auslöst.<br />
Die Platine ist relative einfach aufgebaut. Dadurch kann diese einfach auf einer Laborplatine zusammengelötet werden. Die MaxSonar Sensoren können weggelassen werden und es kann eine eigene Lösung an den Nano angeschlossen werden. Der Sensor für den Druckwellenschlauch kann weggelassen werden und nur der Sonarsensor wird verwendet. Eine anderer Möglichkeit für eine Annährungslösung ist, die aktuelle Raindancer Software zu erweitern.<br />
Die original Ardumower Ultraschall Sensoren werden aktuell nicht unterstützt. <br />
<br />
Für die Bedienung wird das Serielle Interface verwendet. Auf dem Mobile Phone eignet sich die Software Arduino Central (kostenlos mit Werbung oder ohne Werbung für wenige Euros). In Arduino Central können Buttons mit Befehlen konfiguriert werden. Die Bedienung erfolgt über Kommandozeilenbefehle. Die gesendete Zeile muss mit CR abgeschlossen werden. Die Ausgabe erfolgt automatisch auf der Console oder auf dem Mobile Phone, je nachdem von wo gerade der Befehl eingegeben wurde.<br />
Die meisten Befehle sind nach Services Gruppiert. Die Gruppe entspricht den angesprochenen Services in der Software. Der auf den Service folgende Befehl ist dann durch einen Punkt getrennt. Leerzeichen werden übersprungen und haben keine Bedeutung.<br />
Dies ist gerade bei Verwendung des Mobile Phones nützlich, wo ein Leerzeichen nach einem Punkt eingefügt wird.<br />
<br />
Beipiel: clc.enc <br />
Der Service clc enthält den Befehl enc. Damit wird der closes loop control service angesprochen und ihm mittgeteilt, dass er die Encoderdaten anzeigen soll.<br />
<br />
Parameter werden mit einem Komma getrennt.<br />
Beispiel: pc.cm,60,60,30,30 //drives left wheel 60cm at 30% speed and right 60cm at 30% speed (//drives... gehört nicht zum Befehl)<br />
Damit wird der Positioncontrol Service angesprochen. Fahre 60cm mit der Geschwindigkeit von 30%<br />
<br />
Der Befehl H zeigt die Hilfe an.<br />
<br />
Viele Befehle geben Ausgaben auf der Konsole aus. Um diese Ausgabe zu deaktivieren, kann man h eingeben oder den gleichen Befehl wieder (der die Ausgabe angestoßen hat).<br />
Falls ein Error oder Motorstall ausgegeben wird, kann dieser mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Die Software ist Modular aufgebaut. Die einzelnen Module beeinflussen sich fast gar nicht. Damit ist es relative einfach etwas Abzuändern oder zu Erweitern.<br />
https://github.com/kwrtz/Raindancer/blob/master/Documentation/SoftwareStructure.pdf<br />
Zur Dartsellung und Bearbeitung der Software Structure wurde die Software UMLET verwendet.<br />
<br />
Es gibt einen Hardware Abstraction Layer. Die gesamte Kommunikation mit der Hardware erfolgt über Objekte in hardware.h. Die meisten Objekte in hardware.h sind in InOutInterface.h definiert. In hardware.cpp findet die Initialisierung und Pinzuordnung der Hardware statt.<br />
Services sammeln Daten oder steuern die Motoren und stellen ihren Service der Steuerung zur Verfügung. <br />
Als Steuerung wird ein Behaviourtree verwendet. Der Behaviourtree greift auf die Services über das Blackboard zu. Nodes des Behaviourtree tauschen informationen über das Blackboard aus.<br />
<br />
Für die grafische Erstellung des BHT wurde SPLAN verwednet.<br />
https://www.electronic-software-shop.com/elektronik-software/splan-70.html?language=de<br />
Um die Dateien des BHT zu betrachten kann folgende kostenlose Software verwendet werden:<br />
https://www.electronic-software-shop.com/support/kostenlose-datei-viewer/?xoid=oep38ca4ehqn37a7dn3rnrpie6<br />
Die Dateien des BHT befinden sich hier<br />
https://github.com/kwrtz/Raindancer/tree/master/Documentation<br />
<br />
Der Roboter kennt zwei Modi: Manual und Auto. Im manuellen Mode laufen alle Services, aber der Behaviourtree (BHT) ist ausgeschaltet. Im Auto mode wird der BHT aktiviert. <br />
<br />
Welcher Modi wird wann gestartet:<br />
MANUAL Roboter wird eingeschaltet und ist nicht in der Ladestation<br />
AUTO Der Roboter wird in der Ladestation eingeschaltet und erkennt eine Spannung an den Ladekontakten. Das Behaviour Charging wird aktiviert. Der Roboter wird geladen.<br />
<br />
Ist der Roboter im MANUAL Mode, kann er mit dem Befehl A in den Automode geschaltet werden. Erkennt der Roboter dann das Perimetersignal, fängt er an zu mähen.<br />
<br />
==Offene Punkte==<br />
* Stabilität der Software langfristig Prüfen. Stand 28.04.2018 Aktuell hat die aktuelle Softwareversion 63h gemäht, hat dabei 59km zurückgelegt und hat 8426 mal rotiert.<br />
* Der Linienverfolgungsalgorithmus wurde aktuell für das Chassis mit Antriebsrädern hinten optimiert. Aufgrund des kurzen Abstandes von Spule zu den Rädern des original Ardumower Chassis kann es notwendig sein einen anderen Algorithmus zu programmieren. <br />
* Optimierung für das original Ardumower Chassis (Das mähen funktioniert mit dem Workaround schon sehr gut. Ggf. mit den Parametern CONF_PER_CORRECTION_ANGLE und CONF_PERIMETER_DRIVE_BACK_CM etwas spielen)<br />
* Ausweichen von Objekten, die nahe am Perimeter stehen optimieren (SecondReverse2 im BHT)<br />
* Einseitig befahrbare Ladestation umsetzen<br />
* RTC verwenden um Zeitgesteuert zu mähen<br />
<br />
==Weitere Wünsche==<br />
* Regensensor einbinden<br />
* Die Ladestation wird aktuell nur counter clockwise angefahren.<br />
* Verstärken des Signals der Ladestation auf +-20V Spannung Hub<br />
* SRF08 einbinden <br />
* I2C Temperatursensoren einbinden<br />
* Ein externer Start-/Stopknopf der das Mähen startet bzw. stoppt<br />
* Anfahren der Ladestation mit GPS. 15m vor der Ladestation auf den Perimeter fahren und dann in die Ladestation einfahren.<br />
* GPS Karte - es kann sein, dass der Mower das Signal in der Mitte des Rasens nicht erkennt, da das Signal zu schwach ist. Man kann dann mit GPS dann sehen, ob man auf der Fläche ist. Wenn man nun sagt, dass das Signal mindesten in 15m Abstand vom Perimeter erkannt werden muss, kann man es innerhalb der Fläche vernachlässigen wenn das GPS Signal anzeigt, das man auf der Fläche ist.<br />
* GPS Karte - Vermerken wo der Robbi schon gemäht hat. Dann ggf. in weniger gemähten Bereichen mähen.<br />
Die GPS Karte wird vermutlich auf einen externen Prozessor ausgelagert weden müssen.<br />
<br />
=Für eine minimale Inbetriebnahme sollten folgende Voraussetzungen erfüllt sein=<br />
<br />
[[File:warning.png]]Sicherheitshinweis: Aus Sicherheitsgründen sind die Mähmesser bei den ersten Tests [[nicht]] zu montieren!<br />
<br />
[[File:warning.png]]Wichtig: Für die ersten Getriebemotortests sollte der Roboter hochgebockt werden so dass die Räder keinen Kontakt zum Boden haben!<br />
<br />
<br />
*PCB1.3 mit Arduino DUE<br />
*Original Ardumower Antriebsmotoren mit Encoder<br />
*Original Ardumower Mähmotor<br />
*Zwei Ardumower Perimeterspulen vorne Links/Rechts. Bei original Ardumower Chassis ggf. montiert: Links/Mitte (kommt darauf an, welchen Linienverfolgungsalgorithmus man verwendet)<br />
*BT Modul<br />
*Die Brücke für die Encoder auf dem PCB1.3 ist auf den 2er Teiler überbrückt.<br />
*24V Spanungsversorgung<br />
<br />
=Optional kann verwendet werden=<br />
*RTC mit EEPROM<br />
*Ardumower Bumper Pins mit Schaltern, Hall Effekt Sensoren, original Bumper Duino, ...<br />
*Durchfahrende Ladestation <br />
*Selbst gebauter Bumperduino mit 2MaxSonar Sensoren an PinUserSwitch2/3<br />
<br />
=config.h=<br />
Die Datei config.h enthält die Grundkonfiguration der Firmware.<br />
<br />
'''Vor der ersten Inbetriebnahme müssen die Parameter angepasst werden.'''<br />
<br />
Auswahl der Chassisform. Es darf nur ein Parameter true gesetzt werden.<br />
#define ARDUMOWER_CHASSIS true<br />
#define PARANELLO_CHASSIS false<br />
#define RAINDANCER_CHASSIS false<br />
<br />
Danach in config.h die Code-Sektion anpassen, die die Konfiguration für das gewählte Chassis enthält.<br />
Die Sektion beginnt folgendermaßen für das Ardumower Chassis:<br />
//======================================================================================================================<br />
// CONFIG FOR ARDUMOWER CHASSIS<br />
//======================================================================================================================<br />
<br />
Konsolenspeed:<br />
#define CONF_PC_SERIAL_SPEED 115200 // Speed serial consol<br />
<br />
Sollte das Bluetooh Modul bereits mir der Azurit Firmware konfiguriert worden sein, ist die Zeile <br />
#define CONF_BT_SERIAL_SPEED 115200 <br />
auf<br />
#define CONF_BT_SERIAL_SPEED 19200<br />
abzuändern.<br />
<br />
<br />
Einstellen des Radumfangs und Radabstandes. Das original Ardumower Rad hat einen Umfang von 78.54f cm<br />
#define CONF_RADUMFANG_CM 80.738f // Wheel circumfence in cm original ardumower: 78.54f <br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
<br />
<br />
Für die erste Inbetriebnahme sollten die meisten Services deaktiviert werden um Fehlermeldungen zu Verhindern:<br />
<br />
#define CONF_ENABLEWATCHDOG false // Set to false to disable Watchdog. true to enable.<br />
#define CONF_DISABLE_RANGE_SERVICE true // Disables my own range sensor running on bumper duino on pinUserSwitch3 => diNearObsacleSensor<br />
#define CONF_DISABLE_BUMPER_SERVICE true // Disables original bumper sensor pins (PCB1.3) on pinBumperLeft => diBumperL and pinBumperRight => diBumperR<br />
#define CONF_DISABLE_BUMPERDUINO_SERVICE true // Disables my own bumper duino sensor on pinUserSwitch2 => diBumperSensor<br />
<br />
#define CONF_DISABLE_PERIMETER_SERVICE false // Disables perimeter sensor<br />
#define CONF_DISABLE_RTC_SERVICE true // Disables rtc sensor<br />
#define CONF_DISABLE_EEPROM_SERVICE true // Disables EEPROM requests<br />
#define CONF_DISABLE_BATTERY_SERVICE true // Disables battery sensor<br />
#define CONF_DISABLE_CHARGE_SERVICE true // Disables charge system service<br />
#define CONF_DISABLE_RAIN_SERVICE true // Disables rain sensor<br />
#define CONF_DISABLE_DHT_SERVICE true // Disables temp sensor<br />
#define CONF_DISABLE_GPS true // Disables GPS service<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK true // Disables the motor stall/encoder check in closed loop control<br />
#define CONF_DISABLE_MOW_MOTOR false // Disables the mow motor<br />
<br />
#define CONF_DISABLE_CHARGINGSTATION true<br />
<br />
<br />
'''NUR FÜR DAS original Ardumower Chassis Design''' sollten noch folgende Konstanten eingestellt werden, damit dei Drehung am Perimeter optimiert wird:<br />
#define CONF_PER_CORRECTION_ANGLE 30<br />
#define CONF_PERIMETER_DRIVE_BACK_CM 40.0f <br />
<br />
<br />
Da nun häufiger kompiliert wird, ist es sinvoll den Roboter aufzubocken, so dass die Antriebsräder und der Mähmotor frei drehen können.<br />
<br />
Nach dem ersten kompilieren und aufspielen sollte als letzte Zeile folgendes angezeigt werden:<br />
<br />
Press H for help.<br />
<br />
<br />
Hier H eingeben. Danach werden alle verfügbaten Befehle angezeigt. Diese am besten kopieren und abspeichern, so dass man diese einsehen kann.<br />
<br />
<br />
Falls folgende Warnung beim kompilieren auftreten, können diese ignoriert werden:<br />
pinman.cpp: 18:0: warning: "PWM_FREQUENCY" redefined [enabled by default]<br />
#define PWM_FREQUENCY 3900<br />
pinman.cpp: 19:0: warning: "TC_FREQUENCY" redefined [enabled by default]<br />
#define TC_FREQUENCY 3900<br />
<br />
= QUICK START TO MOW =<br />
<br />
Ziel dieses Kapitels ist, mit der Bedienung etwas vertrauter zu werden, und den Roboter soweit zu konfigurieren, dass die Perimeter Sensoren <br />
funktionieren und man innerhalb des Perimeters mähen kann.<br />
<br />
Der Roboter ist über das Konsolenkabel verbunden. Speed: 115200<br />
<br />
==Errorhandling==<br />
Wenn die Firmware einen Fehler feststellt, geht diese in den Errormode. Der Mower bleibt stehen und der Mähmotor wird abgeschaltet. Die Services laufen weiter. Der als erstes aufgetretene Error wird gelatched. <br />
Der Error wird dann alle 2 Sekunden an die Konsole bzw. BT ausgegeben. Je nachdem was als letztes aktiv war oder aktiviert wird durch senden eines Zeichens. Wenn man z.B. den Mower über Bluetooth gestartet hat, wird der Fehler auch auf über BT ausgegeben.<br />
<br />
Zum deaktivieren des Error müssen folgende Befehle nacheinander eingegeben werden:<br />
reset //reset error and motor faults<br />
M //activate manual mode<br />
<br />
Mit dem Befehl error kann sich das Errorlog angezeigt werden. Das Errorlog zeigt die History der durchlaufenen Running Nodes des BHT sowie diverse andere Ereignisse. Es ist 5000 Zeichen groß.<br />
error //show errormessage<br />
<br />
Mit dem Befehl show.hist werden die letzten Drehrichtungen und andere Parameter angezeigt.<br />
show.hist //show history<br />
Die letzten eingetragenen Werte, werden als erstes ausgegeben, so das diese oben stehen!<br />
<br />
Nach dem deaktivieren des Error kann der Mower wieder mit<br />
A<br />
gestartet werden. Dabei müssen sich allerdings beide Spulen im Perimeter befinden.<br />
<br />
==Zum warm werden: Konfiguration des Batterie Service==<br />
Der Batterie Service ermittelt die Spannung der Batterie und stellt diese dem BHT zur Verfügung.<br />
<br />
In config.h den Batterieservice aktivieren und danach die Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_BATTERY_SERVICE false<br />
<br />
Den Befehl <br />
bat.show <br />
eingeben. Es sollte die richtige Batteriespannung angezeigt werden.<br />
<br />
Sollte diese um mehr als 0.2V abweichen, so kann diese mit den Konstanten <br />
#define BATTERYFACTOR_BS 11.0f //Entspricht (100+10)/10 Voltagedivider<br />
#define DIODEDROPVOLTAGE_BS 0.4f<br />
justiert werden. <br />
Diese Konstanten sind in batterySensor.h definiert.<br />
<br />
Berechnet wird die Spannung in batterySensor.h folgendermaßen<br />
<br />
sensorValue = aiBATVOLT.getVoltage(); <br />
float readVolt = sensorValue * BATTERYFACTOR_BS + DIODEDROPVOLTAGE_BS; // The diode sucks 0.4V<br />
<br />
==Inbetriebnahme der Motoren==<br />
Als erstes wird geprüft ob die Motoren sich drehen und ob diese auch in die richtige Richtung drehen.<br />
Dazu werden die Motoren direkt mit einer PWM Vorgabe angesteuert. D.h es erfolgt keine Regelung der Geschwindigkeit anhand der Encoder. Die Regelschleife für die Geschwindigkeit ist offen (open loop);<br />
<br />
Der Befehl clc.mt,1,150 veranlasst den clc Service die eingegebene PWM von 150 direkt an den Motor zu schicken. Maximum für die PWM ist 255.<br />
Die 1 steuert den linken Motor an, die 2 den rechten.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben. <br />
<br />
Damit wird der Motor (1) links direkt mit einer PWM von 150 angesteuert.<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
Das Rad links sollte sich vorwärts drehen. Falls es sich rückwärts dreht muss das Kabel am Stecker umgepolt werden.<br />
Sollten sich das Rad nicht drehen, kann man es noch mit einer höheren PWM von z.B. 200 versuchen. <br />
Das Rad sollte sich auf jeden Fall noch bei einer PWM von 50 (besser weniger) drehen.<br />
<br />
Das gleiche für das rechte Rad (2):<br />
clc.mt,2,150 <br />
<br />
Gestoppt wird das Rad dann mit <br />
clc.mt,0,0<br />
<br />
<br />
Anmerkung: <br />
Die PWM für die Motoren läuft mit 3900Hz. <br />
Wenn man die Originalwerte verwenden möchte, muss man nachfolgende Zeilen in pinman.cpp abändern.<br />
#define PWM_FREQUENCY 3900<br />
#define TC_FREQUENCY 3900<br />
Achtung: Wenn die PWM zu hoch gesetzt wird, z.B. 18000Hz, dann drehen sich die Räder bei niedriger PWM von z.B. 60 nicht mehr. Es kommt dann ein Fehler, dass bei Vorgegebener PWM von 60 die Geschwindigkeit 0 ist.<br />
<br />
==Inbetriebnahme der Encoder==<br />
Es wird geprüft, ob die Encoder funktionieren und ob diese auch in die richtige Richtung zählen.<br />
<br />
Die Encoderroutine hat pro Rad zwei Zähler. Einmal einen Absolutzähler (absEnc), der zählt immer positive egal wie rum sich das Rad dreht.<br />
Und einmal einen positiv/negative Zähler (enc), der bei Vorwärtsfahren hochzählt und bei Rückwärtsfahren runterzählt.<br />
<br />
Den Befehl <br />
clc.mt,1,150 <br />
eingeben, damit sich das linke Rad dreht.<br />
<br />
Dann <br />
clc.enc <br />
eingeben. Damit werden die Encoderwerte vom linken und rechten Rad angezeigt.<br />
<br />
Die Ausgabe wird mit dem Befehl: h beendet.<br />
<br />
Beide angezeigten Zähler des linken Rades (1) müssen nun hochzählen.<br />
<br />
Beispiel:<br />
motor 1 = links -sollte nicht zählen, wenn nur der rechte Motor läuft.<br />
motor 2 = rechts -sollte nicht zählen, wenn nur der linke Motor läuft.<br />
!03,motor 1 enc: 972 absEnc: 972 rpm: 2.596326 m/h: 125.773315 deltaTicks: 2 deltaTime: 32986us<br />
!03,motor 2 enc: 974 absEnc: 974 rpm: 3.325853 m/h: 161.113647 deltaTicks: 2 deltaTime: 33445us<br />
!03,motor 1 enc: 974 absEnc: 974 rpm: 2.923552 m/h: 141.625061 deltaTicks: 2 deltaTime: 33156us<br />
!03,motor 2 enc: 975 absEnc: 975 rpm: 2.678638 m/h: 129.760696 deltaTicks: 1 deltaTime: 33144us<br />
!03,motor 1 enc: 976 absEnc: 976 rpm: 3.132316 m/h: 151.738159 deltaTicks: 2 deltaTime: 32857us<br />
!03,motor 2 enc: 976 absEnc: 976 rpm: 2.296233 m/h: 111.235962 deltaTicks: 1 deltaTime: 32859us<br />
!03,motor 1 enc: 978 absEnc: 978 rpm: 3.251686 m/h: 157.520752 deltaTicks: 2 deltaTime: 32998us<br />
Das Beispiel Zeigt, dass die Encoder hoch zählen. '''Beispiel motor 1''': enc:972 dann enc:974, dann enc:976 ... '''Beispiel motor 2''': enc:972 dann enc:975, dann enc:976 ...<br />
<br />
Falls der enc Wert negative beim Vorwärtsfahren zählt kann man das in der config.h konfigurieren:<br />
#define CONF_LEFT_ENCODER_INVERSE false<br />
#define CONF_RIGHT_ENCODER_INVERSE false<br />
Dazu CONF_LEFT_ENCODER_INVERSE für das linke Rad auf true setzen. Für das rechte Rad CONF_RIGHT_ENCODER_INVERSE auf true setzen.<br />
<br />
Das gleiche für das rechte Rad durchführen:<br />
clc.mt,2,150<br />
<br />
Befehl wird mit clc.mt,0,0 gestoppt.<br />
<br />
Nachdem die Zeilen in der config.h richtig eingestellt wurden, neu kompilieren, aufspielen und neu testen!<br />
<br />
==Check des closed loop control services==<br />
Der closed loop control (clc) service regelt die Geschwindigkeit eines Rades und damit auch das Geradeausfahren des Roboters. Für jedes Rad gibt es einen Service also insgesamt zwei Services. Der Service berechnet intern die Geschwindigkeit des Rades mit Hilfe der Encoderwerte und stellt dann die notwendige PWM ein um die vorgegebene Geschwindigkeit zu erreichen (closed loop). Die Geschwindigkeit wird in % angegeben. Dabei beziehen sich 100% auf die Konstante CONF_MAX_WHEEL_RPM in der config.h.<br />
<br />
Mit dem Befehl clc.v,30 wird beiden Services gesagt, drehe das Rad mit einer Geschwindigkeit(v) von 30%. Somit sollten sich beide Räder vorwärts drehen.<br />
<br />
Eingeben:<br />
clc.v,30 Fährt vorwärts mit Geschwindigkeit 30% <br />
dann<br />
clc.v,s Motor stoppen<br />
dann<br />
clc.v,-30 Fährt Rückwärts mit Geschwindigkeit 30% <br />
<br />
Hat alles funktioniert, dann weiter. Ansonsten nochmal die Encoder und Drehrichtung überpürfen.<br />
<br />
mot.cur Zeigt den Motorstrom an.<br />
<br />
==Check des position control services==<br />
Der Position Control Service (pc) dient dazu, das Rad einen bestimmten Weg zu fahren oder das Rad einen bestimmten Winkel zu drehen. Pro Rad gibt es einen Service.<br />
Mit dem Befehl pc.a,360,80 werden beide Räder angesprochen: Drehe die Räder einen Winkel von 360 Grad mit einer Geschwindigkeit von maximal 80%.<br />
<br />
An einem Rad eine Markierung anbringen, damit man sieht, wie weit es sich dreht<br />
<br />
pc.a,360,80 Rotiert beide Räder vorwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
pc.a,-360,80 Rotiert beide Räder rückwärts um 360 Grad mit 80% Speed wenn alles richtig konfiguriert ist.<br />
<br />
Die Position Control kann mit dem Befehl<br />
pc.s<br />
gestoppt werden.<br />
<br />
<br />
Sollte sich das Rad nicht um 360 Grad gedreht haben, scheint der Wert CONF_ENCTICKSPERREVOLUTION in config.h falsch zu sein. Für die original Motoren aus dem Ardumower Shop ist der Wert von 1060 vorgegeben.<br />
Zusätzlich ist die Konstante CONF_RADUMFANG_CM wichtig, damit die Berechnung für das Fahren eines bestimmten Weges in cm stimmt.<br />
<br />
Da am Anfang in der config.h die Motorüberwachung ausgeschaltet wurde, wird diese nun wieder eingeschaltet.<br />
Die Motorüberwachung prüft, ob die Encoder bei Drehung der Motoren Werte liefern, ob in die richtige Richtung gedreht wird oder ob der Motor überhaupt dreht wenn eine PWM anliegt.<br />
<br />
Zum Einschalten der Morotüberwachung in der config.h den Wert CONF_DISABLE_MOTOR_STALL_CHECK auf false setzen.<br />
<br />
#define CONF_DISABLE_MOTOR_STALL_CHECK false<br />
<br />
Neu kompilieren und aufspielen. Dann nochmal probieren.<br />
Es dürfen keine Fehler angezeigt werden.<br />
<br />
<br />
Wenn alles funktioniert hat, kann der Roboter auf die Räder gestellt werden. <br />
<br />
Weiter Tests können noch durchgeführt werde (Achtung, das USB Kabel sollte lang genug sein. Am besten eine Verlängerung verwenden);<br />
<br />
Zurücklegen einer bestimmten Streck in cm<br />
<br />
pc.cm,60,60,30,30 Fahre 60cm vorwärts mit der Geschwindigkeit von 30%<br />
<br />
pc.cm,-60,-60,30,30 Fahre 60cm rückwärts mit der Geschwindigkeit von 30%<br />
<br />
<br />
<br />
Drehen eines bestimmten Winkels. Voraussetzung: CONF_ENCTICKSPERREVOLUTION, CONF_RADUMFANG_CM, und CONF_DISTANCE_BETWEEN_WHEELS_CM sind richtig konfiguriert.<br />
<br />
turnto,360,30 Drehe den Roboter um 360 Grad CW (clockwise)<br />
<br />
turnto,-360,30 Drehe den Roboter um 360 Grad CC (counter clockwise)<br />
<br />
Sollte der Roboter nicht 360 Grad drehen, so ist vermutlich die Konstante CONF_DISTANCE_BETWEEN_WHEELS_CM in config.h falsch eingestellt.<br />
<br />
==Mähmotor Inbetriebnahme==<br />
Der Mähmotor verwendet keinen Encoder. Er wird mit einer PWM von 255 betrieben. Die PWM von 255 wird nicht sofort auf den Motor gegeben. Es wird über eine Rampe die PWM von 0 auf 255 erhöht.<br />
Das gleiche gilt für das Abbremsen des Motors. Es kann vorkommen, das bei dem Abbremsen des Motors ein Motorfault angezeigt wird. Dies liegt daran, dass die Motorscheibe durch die Trägheit versucht den Motor weiter zu drehen und dieser somit einen Storm in den Motortreiber rückwirkend einspeist, welcher die Limits überschreitet so dass die Tri State Ausgänge des des Treibers in den hochohmige Zustand gehen. Sollte das passieren kann der Fehler mit dem Befehl reset zurückgesetzt werden.<br />
<br />
Befehl eingeben:<br />
z //mow motor start<br />
<br />
danach<br />
t //mow motor stop<br />
<br />
Es kann sein, dass beim stoppen ein motorfault kommt. Diesen mit reset zurücksetzen.<br />
<br />
mot.curm //zeigt den Mähmotorstrom an.<br />
<br />
<br />
Wenn das PCB1.3 verwendet wird, wird hier der Mähmotorstrom vermutlich falsch angezeigt. Siehe dazu: Mähmotorstrom einstellen in Tune Up<br />
Dies kann später durchgeführt werden und ist für den ersten Mähbetrieb nicht so wichtig.<br />
<br />
==Perimeter Inbetriebnahme==<br />
Die Raindancer Firmware arbeitet mit zwei Spulen. Damit wird festgestellt, in welchem Winkel der Roboter auf den Perimeter triff. Dementsprechend wird entschieden, ob CC oder CW gedreht wird. Das Perimetersignal muss die ganze Zeit während des Mähens empfangen werden. Wird für 2 Sekunden das Signal nicht empfangen, stoppt der Roboter und fährt weiter, sobald das Signal wieder empfangen wird. Die Zeit, die ein nicht Empfang toleriert wird, wird mit dem Parameter CONF_PER_SIGNAL_LOST_TIME in der config.h festgelegt. So kann mann ggf. "Empfangslöcher" in der Mitte des Rasen überbrücken. Nachteil ist, falls der Sender genau dann ausfällt wenn sich der Roboter am Perimeter befindet, kann es sein, dass der Roboter diese eingestellte Zeit außerhalb der Perimeterschleife fährt.<br />
<br />
Voraussetzung zur Inbetriebnahme:<br />
Die Spulen des Roboters müssen für die Inbetreibnahme innerhalb der Perimeterschleife sein.<br />
Die Raindancer Sender Firmware muss auf dem Sender installiert sein.<br />
<br />
Als erstes wird geprüft, ob das Signal erkannt wird.<br />
<br />
Man kann sich die berechneten Wert der einzelnen Spulen folgendermaßen anzeigen lassen:<br />
per.resultl für linke Spule und per.resultr für rechte Spule. <br />
Am Beispiel unten kann man am BAD erkennen, dass kein gültiges Signal empfangen wurde.<br />
Wichtig ist hier, dass kein BAD angezeigt wird. Die empfangene Amplitude steht hinter mag:. Die Signalqualität kann man an der Peak Signal Noise Ratio psnr sehen.<br />
<br />
Beispiel per.resultl<br />
mag: 453 peak @ 432 : 453 peak2 @ 328 : 142 MSE: 1704.569 psnr: 120.388 psnr2: 11.829 ratio: 10.177<br />
mag: 431 peak @ 279 : 431 peak2 @ 145 : -125 MSE: 1638.841 psnr: 113.349 psnr2: 9.534 ratio: 11.889<br />
mag: 372 peak @ 128 : 372 peak2 @ 12 : 119 MSE: 1521.076 psnr: 90.978 psnr2: 9.310 ratio: 9.772<br />
mag: 458 peak @ 486 : 458 peak2 @ 352 : -195 MSE: 1922.495 psnr: 109.110 psnr2: 19.779 ratio: 5.516<br />
mag: 428 peak @ 335 : 428 peak2 @ 233 : 118 MSE: 1818.376 psnr: 100.740 psnr2: 7.657 ratio: 13.156<br />
<br />
Beispiel per.resultr <br />
mag: 6 peak @ 144 : 6 peak2 @ 24 : -5 MSE: 3.161 psnr: 11.388 psnr2: 7.908 ratio: 1.440 BAD<br />
mag: -5 peak @ 161 : -5 peak2 @ 46 : 4 MSE: 2.380 psnr: 10.504 psnr2: 6.723 ratio: 1.562 BAD<br />
mag: -5 peak @ 60 : -5 peak2 @ 179 : 5 MSE: 3.556 psnr: 7.030 psnr2: 7.030 ratio: 1.000 BAD<br />
mag: 5 peak @ 159 : 5 peak2 @ 3 : 4 MSE: 2.949 psnr: 8.477 psnr2: 5.425 ratio: 1.563 BAD<br />
mag: 5 peak @ 11 : 5 peak2 @ 153 : 5 MSE: 3.286 psnr: 7.607 psnr2: 7.607 ratio: 1.000 BAD<br />
<br />
Mit h Ausgabe beenden.<br />
<br />
Beide Spulen sollten das Signal erkennen, also kein BAD anzeigen. Auch nicht sporadisch!<br />
<br />
<br />
Als nächstes muss die Polarität des Signals konfiguriert werden.<br />
<br />
per.show eingeben. (mit h Ausgabe ausschalten)<br />
<br />
Wenn die Spule innerhalb des Perimetes ist, muss die Amplitude der Spule positive sein.<br />
<br />
Es werden nun die erkannten Perimeteramplituden ausgegeben.<br />
ML zeigt die Amplitude der linken Spule an, MR die Amplitude der rechten Spule.<br />
<br />
!03, ML: -305 MR: 331 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -330 MR: 338 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -327 MR: 330 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -336 MR: 332 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -304 MR: 328 magMax:332 magMedL%: 0 magMedR%: 102<br />
!03, ML: -326 MR: 324 magMax:332 magMedL%: 0 magMedR%: 102<br />
<br />
Allerdings sieht man hier, dass die Magnetude links negative ist. <br />
In der Perimeterschleife muss diese positive sein. <br />
<br />
Dies kann in der config.h eingestellt werden:<br />
#define CONF_LEFT_COIL_INVERSE true<br />
#define CONF_RIGHT_COIL_INVERSE false<br />
<br />
Nach neuem aufspielen, sollten die Werte positive sein.<br />
<br />
<br />
Achtung, bei per.resultl und per.resultr wird das Vorzeichen der Amplitude wie tatsächlich empfangen angezeigt unabhängig von den Einstellungen in CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE. <br />
Es kann sein, dass per.resultl eine positive Amplitude liefert und per.resultr eine negative. Das ist OK, da es von dem Anschluss der Spulen abhängt. Die Umrechnung mit CONF_LEFT_COIL_INVERSE/CONF_RIGHT_COIL_INVERSE findet in der Software später statt. <br />
Wichtig ist, das CONF_LEFT_COIL_INVERSE und CONF_RIGHT_COIL_INVERSE so konfiguriert werden, dass per.show innerhalb des Perimeters positive Amplituden anzeigt.<br />
<br />
==Konfiguration Bluetooth==<br />
<br />
Wurde das Modul bereits mit der original Arduower Software konfiguriert, kann<br />
#define CONF_BT_SERIAL_SPEED 19200 <br />
eingestellt werden.<br />
(Die Perimeterausgaben sind extrem umfangreich. Es kann sein, das die Software bei dieser Übertragungsrate ins Stocken gerät, wenn man sich Perimeterdaten über BT bei dieser Baudrate anzeigen läßt.)<br />
Damit wäre dann die Konfiguration fertig.<br />
<br />
<br />
Da es häufiger Probleme mit der Konfiguration von BT Modulen gibt, schlage ich vor ein funktionierendes BT Modul nur dann umzuprogrammieren, wenn man noch ein anderes funktionierendes BT Modul als Reserve hat.<br />
<br />
<br />
Für die Konfiguration des BT wird die original Ardumower Routine verwendte. Allerdings wird die Baudrate auf 115200 gesetzt.<br />
Daher kann man die zur Fehlersuche verwendeten Tips im Forum verwenden.<br />
<br />
Also los:<br />
Platine stromlos schalten (auch USB vom DUE abziehen). Knopf auf BT Modul drücken und gedrückt halten. Platine anschalten.<br />
Das BT Module sollte nun alle 2Sek blinken. <br />
<br />
Knopf loslassen. USB an den DUE wieder anschließen. Das BT Modul sollte immer noch im 2Sek. Takt blinken.<br />
<br />
Nun als erste mit bt.show versuchen, ob das BT Modul gefunden wird:<br />
bt.show <br />
<br />
Wenn erfolgreich gefunden:<br />
<br />
bt.set <br />
eingeben. Das BT Modul wird konfiguriert.<br />
<br />
==Einstellen Arduino Central==<br />
Die Software läuft auf einem Android Mobilephone oder Tablet.<br />
Arduino Central kann aus dem Play Store heruntergeladen werden. Eine andere Software die auch funktioniert ist Serial Bluetooth Terminal.<br />
<br />
In Arduino Central kann oben rechts das Menü (drei Punkte) aufgemacht werden. Dort Settings aufrufen.<br />
<br />
Dann Button layout Configuratin öffnen. Hier wird eingestellt, welche Buttons angezeigt werden.<br />
Nur folgendes soll angewählt sein:<br />
Show Control Button<br />
Show Standard Button set 1<br />
Show Standard Button set 2<br />
Show Standard Button set 3<br />
<br />
Zurückgehen und Serial Terminal Settings öffnen<br />
Terminal View Character Limit auf 10000 setzen<br />
<br />
Zurückgehen und Line Ending for Commands auswählen<br />
Hier CR auswählen<br />
<br />
Zurückgehen und Line Ending for Incomming Data auswählen<br />
Hier NL auswählen.<br />
<br />
Dann erstmal ganz aus dem Menü rausgehen.<br />
<br />
Als erstes muss nun das BT Modul mit dem Handy gekoppelt werden.<br />
Das heißt am Handy BT Aktivieren. <br />
Dann in das BT Menue am Handy gehen und nach neuen Geräten suchen. <br />
Dort sollte dann eine neues Gerät auftauchen. Dieses Geräte auswählen und paaren bzw koppeln.<br />
Es kommt zu einer Passwortabfrage die 1234 ist oder auch 0000<br />
Danach wird das Modul in der Gerätelist aufgenommen. <br />
<br />
Jetzt in Arduino Cnetral im Menü auf connect to Device gehen und das BT des Robbis klicken.<br />
Wenn alles erfolgreich war, sollte oben rechts BT connect angezeigt werden.<br />
<br />
In der Befehlszeile dann H eingeben und Senden. Es sollte dann die Hilfe angezeigt werden.<br />
<br />
In Arduino Central können unter dem Menüpunkt Standard Button Setup Befehle hinterlegt werden.<br />
Aktuell habe ich bei mir folgende Befehle hinterlegt:<br />
Button 1 Text: Manual Command: M<br />
Button 2 Text: Auto Command: A<br />
Button 3 Text: Hide Command: h<br />
Button 4 Text: area,19 Command: area,19<br />
Button 5 Text: gohome Command: gohome<br />
Button 6 Text: per Command: per.show<br />
Button 7 Text: mowense Command: mot.curm<br />
Button 8 Text: bat Command: bat,show<br />
Button 9 Text: charge Command: charge.show<br />
<br />
Diese Befehle können je nach Bedarf angepasst werden.<br />
<br />
==Erste Testfahrt==<br />
Dazu zur Sicherheit für den ersten Test den Mähmotor in config.h ausschalten.<br />
<br />
#define CONF_DISABLE_MOW_MOTOR true<br />
<br />
Danach neu kompilieren und Software aufspielen.<br />
<br />
Achtung, es sind noch keine Bumper aktiv! D.h. die Fläche innerhalb des Perimeters muss frei sein.<br />
<br />
Das USB Kabel abziehen und eine Verbindung mit Arduino Central herstellen.<br />
<br />
Roboter in die Schleife stellen. <br />
Mit show.per nochmal das Perimetersignal überprüfen. Mit h oder show.per Ausgabe deaktivieren.<br />
<br />
A für Auto eingeben um das mähen zu starten.<br />
<br />
Es kann nun 5 Sek. dauern bis sich etwas tut. Der Roboter fährt erst den Mähmotor hoch. Da dieser abgeschaltet ist, kann es so aussehen, als ob nicht passiert.<br />
<br />
M eingeben für manuellen mode, um den Roboter zu stoppen.<br />
<br />
=TUNE UP =<br />
<br />
==Konfiguration der Bumper an den Bumperanschlüssen==<br />
Das original Ardumower Chassis liefert keine standardmäßige Lösung für Bumper mit. Da die meisten Anwender sich hier eigene Lösungen schaffen, bietet die Software entsprechende Optionen an, die Bumper über die vorgesehenen Pins abzufragen.<br />
<br />
Zum aktivieren der Bumper muss in der config.h folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_BUMPER_SERVICE false<br />
<br />
<br />
Zum Testen der Bumper kann man den Befehl bumper.show verwenden. Der Bumper Service gibt dann auf der Konsole oder dem Mobile Phone seine Aktivität aus, je nachdem von wo dieser Befehl gesendet wurde.<br />
bumper.show <br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert. Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
Der Bumperservice kann mir folgenden Parametern in der config.h konfiguriert werden:<br />
<br />
<br />
Verwenden des linken oder/und rechten Bumpers<br />
<br />
#define CONF_USE_LEFT_BUMPER true // left bumper is used<br />
#define CONF_USE_RIGHT_BUMPER true // right bumper is used<br />
<br />
<br />
Festlegen, ob der Bumper aktiv ist, wenn der Pin auf GND gezogen wird:<br />
<br />
#define CONF_LEFT_BUMPER_LOW_ACTIVE true // left bumper is activated when pin is low<br />
#define CONF_RIGHT_BUMPER_LOW_ACTIVE true // right bumper is activated when pin is low<br />
<br />
<br />
Wenn man eine linken und einen rechten Bumper verwendet, gibt es noch die Möglichkeit zu konfigurieren, dass die Drehrichtung nach zurückfahren vom aktivierten Bumper bestimmt wird. D.h. dass wenn der linke Bumper betätigt wurde, der Roboter sich dann nach dem Zurückfahren rechts dreht. <br />
<br />
#define CONF_ESCAPEDIR_DEPENDING_ON_BUMPER false // if set to true, the robot rotates in the opposite direction of the activated bumper. If false, the escape direction is random.<br />
// only set to true if you use a bumper for left and a bumper for right.<br />
<br />
<br />
<br />
Die Bumper Pins sind standardmäßig als Eingänge mit Pullup Widerstand konfiguriert in hardware.cpp:<br />
<br />
DigitalIn diBumperL(pinBumperLeft, true);<br />
<br />
DigitalIn diBumperR(pinBumperRight, true);<br />
<br />
Das bedeutet, der Eingang ist standardmäßig auf HIGH, wenn der Pin nicht auf GND gezogen wurde.<br />
<br />
<br />
''Möchte man die Pullupwiderstände ausschalten, müssen die Zeilen folgendermaßen geändert werden''<br />
<br />
''DigitalIn diBumperL(pinBumperLeft, false);''<br />
<br />
''DigitalIn diBumperR(pinBumperRight, false);''<br />
<br />
==Charge Service==<br />
Der Charge Service stellt dem BHT die Charge Voltage und den Charge Current zur Verfügung. Er enthält Funktionen zum Ein-/Ausschalten des Laderelais.<br />
<br />
Anmerkung:<br />
Wenn den Mower ausgeschaltet ist (also Batterie nicht angeklemmt) und dann an P42 Charger eine Ladespannung angeschlossen wird,<br />
wird das Board über D73 direkt mit Spannung versorgt. Das Problem ist, das die Kondensatoren auf dem Board keine Spannung haben und beim Anklemmen einen Kurzschluss liefern. Dann wird eine 1,6A Sicherung in EF1 durchschlagen.<br />
Daher sollte EF1 5A betragen.<br />
Ich habe bei mir die D73 entfernt, da ich diese nur dann für sinnig halte, wenn die Batterie so leer ist, dass das Board und Relay nicht mehr mit der Batterie funktioniert. Falls dies mal wirklich <br />
passiert, werde ich die Batterie direkt mit dem Ladegerät laden. Sowas sollte nur im Fehlerfall passieren und nicht die Regel sein (Ich möchte aber niemanden überreden dies auch zu tun).<br />
Weiterhin hat die D73 ein anders Potential auf der Hinterseite, als die Dioden die hinter dieser eingelötet sind. Da ist es sinnig, diese mit Heißkleber zu trennen, nicht das diese aneinander geraten.<br />
<br />
[[Im Folgenden wir beschrieben, wie man den Roboter laden kann]]<br />
<br />
'''Selbstständiges Fahren in die Ladestation'''<br />
<br />
Wenn der Roboter in die Ladestation fährt, ist das Laderelais ausgeschaltet. Zu diesem Zeitpunkt liegt nur die Spannung der Ladestation an den Kontakten.<br />
Hat der Roboter dies festgestellt, stoppt er, wartet zwei Sekunden und überprüft die Ladespannung nochmal. Wenn diese OK ist, fährt er 3cm vorwärts, 3cm rückwärts und wieder 2cm vorwärts.<br />
Dies dient dazu die Verbindung zu den Ladekontakten zu optimieren (die aktuell als Schleifkontakte ausgeführt sind). Danach wird das Relay eingeschaltet und die Ladespannung erneut geprüft. <br />
(Dieses Verhalten kann ohne großen Aufwand im BHT umprogrammiert werden.) Das Relay bleibt solange angezogen und damit die Batterie mit dem Ladegerät verbunden, bis der Roboter den Befehl bekommt zu einem Bereich (area) zu fahren oder der Roboter in den manuellen Mode geschaltet wurde oder in den auto Mode geschaltet wird.<br />
<br />
'''Verwenden ohne Ladestation'''<br />
<br />
Um den Roboter zu laden sollte dieser sich im Manual mode befinden (Befehl M eingeben). Danach kann man mit charge.relay,1 das Relay einschalten und mit charge.relay,0 das Relay ausschalten. Das Relay schaltet automatisch aus, wenn man den Auto Modus aktiviert. '''Das Relay schaltet nur ein, wenn an den Ladekontakten die Ladespannung anliegt!'''.<br />
Eine andere Möglichkeit ist, die Ladekontakte im ausgeschaltetem Zustand anzuschließen und den Roboter dann einzuschalten. Der Roboter geht dann in den Auto mode uns schaltet das Behaviour Charging Station ein. Damit denkt er nun, er ist in der Ladestation. <br />
<br />
'''Einstellen in die Ladestation'''<br />
<br />
Hier den Roboter im ausgeschalteten Zustand in die Ladestation stellen, so dass die Ladekontakte Kontakt haben. Dann einschalten. Der Roboter geht dann in den Auto mode in das Behaviour Charging Station. Damit denkt er nun, er ist in der Ladestation, schaltet das Relais ein und lädt.<br />
<br />
<br />
Um den Chargingservice zu aktivieren inder config.h CONF_DISABLE_CHARGE_SERVICE auf false setzen und Software neu aufspielen.<br />
<br />
#define CONF_DISABLE_CHARGE_SERVICE false<br />
<br />
[[Manuelles Testen:]] <br />
<br />
Den Befehl<br />
charge.show <br />
eingeben. Damit werden die Spannungen und Ströme kontinuierlich angezeigt. Aktuell sollte alles mit 0 angezeigt werden.<br />
<br />
Ladegerät an P42 oder Ladekontakte anschließen.<br />
<br />
Nun sollten die Chargevoltage (CV) angezeigt werden.<br />
<br />
Relay einschalten:<br />
charge.relay,1<br />
<br />
Damit fließt nun ein Strom vom Ladegerät zur Batterie und ein Charge Current wird angezeigt (CC). <br />
<br />
Relay ausschalten.<br />
charge.relay,0 <br />
<br />
<br />
[[Testen im ausgeschaltetem Zustand über die Konsole:]]<br />
<br />
Roboter einschalten und USB anschließen. Warten bis Software hochgelaufen ist. <br />
Ladekontakte verbinden. <br />
Serielle Konsole öffnen. Der DUE startet neu. Das Relay sollte angezogen werden und die Konsolenausgabe beim Booten sollte "Charging station detected" anzeigen.<br />
Der Roboter hat nun in das Chargingbehaviour geschaltet.<br />
<br />
M eingeben um wieder in manuellen mode zu gelangen und das Relay abzuschalten.<br />
<br />
==Watchdog==<br />
Der Watchdog dient ausschließlich zur Sicherheit.<br />
Falls sich die Software aufhängt, soll der Watchdog verhindern, dass der Roboter unkontrolliert weiterläuft. <br />
Der Watchdog ist hardwaretechnisch im DUE realsiert. Er wird in der config.h mit <br />
#define CONF_ENABLEWATCHDOG true<br />
aktiviert.<br />
<br />
Jedesmal wenn der Loop durchlaufen wird, wird der Watchdog mit dem Funktionsaufruf watchdogReset(); reseted. <br />
Wenn watchdogReset(); innerhalb von 3 Sek. nicht aufgerufen wird (weil die Software irgendwo hängt), wird der DUE neu gestartet, die Motoren gestoppt und die Software geht in den Modus Manual.<br />
<br />
Anmerkung:<br />
Da die Variablen der Firmware beim Reboot neu initialisiert werden, ist es schwer herauszufinden, was die Ursache des Fehlers ist. <br />
Der Mower bleibt einfach stehen, und man wundert sich beim Öffnen der BT Verbindung, das alles in Ordnung ist und kein Fehler ausgegeben wird - außer das die Software im Manual Mode ist.<br />
<br />
== Unterspannungsabschaltung ==<br />
Die Unterspannungsabschaltung dient dazu zu verhindern, dass die Batterie unter eine bestimmte Spannung fällt und dann Tiefen entladen wird. Die Umsetzung der Unterspannungsabschaltung ist im Batterie Service implementiert. <br />
Voraussetzung ist, das Hardwareseitig der Jumper 8 UV-Abschaltung auf PCB 1.3 auf Auto gestellt ist. Wenn man dann Spannung auf das Board gibt, bekommt dieses erstmal keinen Strom. Daher muss beim Einschalten der Spannung die UV-Abschaltung mit dem P20 Button überbrückt werden. Dann bekommt das PCB1.3 Spannung. Dieser Button sollte so für 4 Sekunden gehalten werden. Dann übernimmt die Software die Steuerung der UV-Abschaltung. Der P20 Button muss danach wieder offen sein, ansonsten kann die Software die Spannung nicht abschalten.<br />
<br />
<br />
In der config.h ist die Schwelle eingestellt, bei der die Spannung abgeschaltet wird<br />
#define CONF_VOLTAGE_SWITCHOFF_BS 21.7f <br />
Wenn die Batteriespannung für eine Minute unter diese Spannung abfällt, wird die Spannung zum PCB1.3 und den Motoren abgeschaltet.<br />
Das gesamte PCB1.3 ist dann dunkel.<br />
<br />
Möchte man die Unterspannungsabschaltung überbrücken, kann man Jumper 8 auf Dauer-An stellen oder P20 überbrücken. Ich habe am P20 einen Ein-/Ausschalter angeschlossen, so das ich für Testzwecke diesen überbrücken kann. Der Jumper 8 steht weiterhin auf Auto.<br />
<br />
==I2C Bus==<br />
Der I2C Bus kann mit dem Befehl i2c.scan gescannt werden. Es werden dann alle gefundenen Adressen angezeigt.<br />
<br />
i2c.scan<br />
<br />
Die Adressen des RTC Moduls und des EEPROM können in der hardware.cpp angepasst werden. Zur Zeit sind die Standardadressen konfiguriert:<br />
<br />
byte DS1307_ADDRESS = B1101000;<br />
byte AT24CX_ADDRESS = B1010000;<br />
<br />
==RTC==<br />
Das RTC Modul wird zur Zeit nicht verwendet. Es ist vorgesehen, später dieses für einen zeitlichen Mähstart zu verwenden.<br />
Das RTC Modul kann aber bereits programmiert und getestet werden.<br />
<br />
Das RTC Modul wird mit folgender Zeile in der config.h aktiviert:<br />
<br />
define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Es stehen folgende Befehle zur Verfügung:<br />
rtc.show //show rtc values every rtc read (10sec)<br />
rtc.config //show rtc service config<br />
rtc.find //tries to find RTC and show result<br />
rtc.set,8,17,3,25,01,2017 //set rtc time=8:17 dayOfWeek=3 date=25.01.2017<br />
<br />
==EEPROM==<br />
Es wird das EEPROM auf dem RTC verwendet. Zur Zeit wird es verwendet um Statistiken abzuspeichern. Es werden folgende Statistiken abgespeichert: Gesamte Mähzeit, Gesamte gefahrene Strecke, Gesamte Anzahl an Rotationen, Anzahl Ladevorgänge.<br />
<br />
Die Verwendung des EEPROM wird mit folgender Zeile in der config.h eingeschaltet:<br />
<br />
#define CONF_DISABLE_EEPROM_SERVICE false<br />
<br />
Folgende Befehle stehen für das EEPROM zu Verfügung:<br />
<br />
eep.config //show EEPROM service config<br />
eep.u8t,10 //show uint8_t at address 10<br />
eep.s32t,10 //show int32_t at address 10<br />
eep.f,10 //show float at address 10<br />
eep.set.u8t,10,7 //write value uint8_t=7 to address=10 <br />
eep.set.s32t,10,1234 //write value int32_t=1234 to address=10 <br />
eep.set.f,10,7.3 //write value float=7.3 to address=10 <br />
eep.erase //erase the eeprom<br />
<br />
Zum testen des EEPROM z.B. folgenden Befehl eingeben:<br />
eep.set.f,10,7.3<br />
Damit wird der float Wert 7.3 an die Adressen 10,11,12,13 in das EEPROM geschrieben.<br />
<br />
Mit dem Befehl <br />
eep.f,10<br />
kann der Wert dann wieder ausgelesen werden.<br />
<br />
Der Befehl eep.erase löscht die ersten 3 Pages des EEPROM. Die anderen Pages werden aktuell nicht gelöscht, da diese nicht verwendet werden.<br />
eep.erase<br />
<br />
Es ist sinnvoll das EEPROM nach dem enablen zu löschen, damit die Speicherzellen initialisiert werden.<br />
<br />
==Geschwindigkeit am Perimeter verlangsamen==<br />
Der Mower fährt mit einer Geschwindigkeit von 1200m/s. Um das Abbremsen beim Überfahren des Perimeters etwas sanfter durchzuführen, verringert der Roboter kurz vor dem Perimeter (ca. 20cm) die Geschwindigkeit. <br />
<br />
Folgende Konstanten in der config.h beeinflussen das Erkennen nahe am Perimeter:<br />
#define CONF_NEAR_PER_UPPER_THRESHOLD 80.0L // Threshold of one coil where Perimetersignal is detected as near perimeter<br />
#define CONF_NEAR_PER_LOWER_THRESHOLD 70.0L // Threshold of the other coil where Perimetersignal is detected as near perimeter<br />
<br />
<br />
Um festzustellen, ob der Roboter nahe am Perimeter ist, wird die Amplitude der linken und rechten Spule ausgewertet. Dazu ermittelt die Firmware die aktuelle maximale Amplitude über die gesamte Fahrzeit des Mower. Wenn nun die linke Spule eine Amplitude von 80% (CONF_NEAR_PER_UPPER_THRESHOLD) oder höher des Maximalwertes erreicht und die rechte Spule über 70% (CONF_NEAR_PER_LOWER_THRESHOLD) oder höher des Maximalwertes erreicht, so wird angenommen, dass der Roboter nahe am Perimeter ist. Das Gleiche gilt, wenn die rechte Spule 80% erreicht und die linke 70%.<br />
<br />
Diese Werte sind abhängig von der verwendeten Spule und von der eingestellten Signalstätke des Sender und müssen daher ggf. nachjustiert werden.<br />
<br />
Um dies zu justieren, den Befehl per.show eingeben während der Mower fährt.<br />
per.show <br />
Wenn er dann über den Perimeter fährt den gleichen Befehl eingeben oder h drücken. Dann in der Anzeige zurück scrollen und sich die Werte angucken.<br />
<br />
Beispiel:<br />
!03, ML: 305 MR: 331 magMax:332 magMedL%: 73 magMedR%: 87<br />
<br />
Die Werte magMedL%: 73 magMedR%: 87 zeigen hier die gemessene Prozentzahl der Spulen an. Hiernach dann CONF_NEAR_PER_UPPER_THRESHOLD und CONF_NEAR_PER_LOWER_THRESHOLD einstellen. Es sollten mehrere Versuche zur Bestimmung durchgeführt werden. Besser etwas früher langsamer werden, als zu spät. Der Unterschied zwischen High und Low wurde eingeführt, da die Spulen nicht den gleiche Wert haben, z.B. wenn der Mower schräg oder fast parallel zum Perimeter fährt.<br />
<br />
Es kann sein, dass magMedL% und magMedR% mehr als 100% anzeigen. Dies beruht auf der Art der magMax Ermittlung und ist OK.<br />
<br />
Die Berechnung ist in der Funktion '''bool TPerimeterThread::isNearPerimeter()''' in der Datei perimeter.cpp hinterlegt.<br />
<br />
==Mähmotorstrom einstellen==<br />
Es ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers auf dem PCB1.3 zusammengeschaltet wurden. <br />
<br />
Bei mir wird bei einer PWM von 255 am Mähmotor fast kein Strom gemessen. Habe dann mal mit einem Multimeter nachgemessen. Am M2 FB liegen tatsächlich im vollen Leerlauf nur 0.04V an. Richtig wären ca. 0.22V da der Motor hier 0,41A zieht. Am M1 FB1 messe ich eine Spannung von 0.007V. Es scheint so, dass durch das parallel Schalten die Strommessung nicht mehr stimmt. Man könnte meinen diese sollte sich halbieren. Ist aber nicht so. <br />
<br />
<br />
Eine Zusammenschaltung der beiden MC33926 wird vom Hersteller nicht ausdrücklich empfohlen und liefert scheinbar eine falsche Strommessung.<br />
<br />
https://www.nxp.com/docs/en/application-note/AN4833.pdf<br />
<br />
Zitat:"If two independent H-bridges are used (separate MC33926 or similar), the load sharing may not be quite as even,<br />
<br />
resulting in a reduction in maximum drive capability. This configuration will latch any fault until the EN pin is toggled."<br />
<br />
<br />
Ich habe dann vom Mowmotortreiber die Pins M1 OUT1 und M1 OUT2 abgeklemmt (gebogen und neben die Buchsenleist geführt, so das diese keinen Kontakt haben). Und siehe da, die Strommessung funktioniert richtig, wobei unter 1A diese nicht wirklich genau ist. Erst ab 1A ist der Wert zuverlässig.<br />
<br />
Forumseintrag:<br />
https://www.ardumower.de/index.php/de/forum/ardumower-1-3-mainboard/1461-pcb1-3-motorstrom-wird-vermutlich-falsch-gemessen#13904<br />
<br />
<br />
Wenn M1 OUT1 und M1 OUT2 nicht abgeklemmt werden wird der Strom zu gering angezeigt.<br />
Daher muss der scale Wert für die richtige Strommessung in der setup Funktion der Klasse TMowMotorSensor in der Datei mowmotorSensor.h angepasst werden.<br />
Der scale factor sollte bei Strömen um die 1A oder mehr eingestellt werden. D.h. die Mähscheibe muss belastet werden, wenn man mit dem Multimeter den Strom misst.<br />
<br />
Wenn M1 OUT1 und M1 OUT2 abgeklemmt werden ist der Faktor den ich durch Messen eingestellt habe vermutlich einigermaßen richtig. Dies kann aber nur durch Nachmessen von Stromstärken ab 1A überprüft werden.<br />
<br />
Der gemessene Strom und die Wattzahl wird mit dem Befehl<br />
mot.curm <br />
angezeigt.<br />
<br />
==Langsamer fahren, wenn Mähmotor belastet==<br />
Wenn der Mähmotor belastet ist, wird der Mower langsamer. <br />
<br />
Ab welcher Wattzahl des Mähmotors langsamer gefahren wird, wird in der config.h mit dem Parameter<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f <br />
eingestellt. Wenn der Mähmotor über 30W benötigt, wird die Geschwindigkeit verlangsamt.<br />
<br />
Die aktuelle Watt Zahl beim Mähen kann mit dem Befehl<br />
mot.curm <br />
angezeigt werden. Danach kann der Wert nach eigenem Ermessen eingestellt werden.<br />
<br />
Achtung, die Motordriver liefern eine genaue Strommessung erst ab 1A (lt. Datenblatt 0.5A). <br />
D.h. Werte wo der Strom unter 1A angezeigt wird sind ungenau und sollten nicht verwendet werden.<br />
Die Genauigkeit beträgt lt. Datenblatt bei einem Strom von über 0.5A +-20%. <br />
<br />
Der Code für die Geschwindigkeitseinstellung befindet sich in der Klasse class TCruisePerimeterNear : public Node in der Datei bCruise.h.<br />
<br />
Weiterhin ist zu berücksichtigen, dass die Ausgänge des Mähmotordrivers zusammengeschaltet wurden. Dies wird vom Hersteller nicht empfohlen und liefert eine falsche Strommessung.<br />
<br />
==Spiralfahrt==<br />
Wenn der Mähmotor belastet wird, kann eine archimedische Spiralfahrt aktiviert werden. Dabei wird beim Start bereits mit einer kleinen Kurve begonnen, so dass das innere Rad sich dreht. Daher bleibt in der Mitte der Spirale ein kleiner Grasbüschel stehen.<br />
<br />
Die Spirale wird in der config.h mit folgender Zeile aktiviert:<br />
#define CONF_ACTVATE_AUTO_SPIRAL true<br />
<br />
Die unten aufgeführten Prameter können nach eigenem wünschen angepasst werden. Wenn die Spirale zu häufig gedreht wird, kommt der Roboter nicht von der Stelle und bearbeitet nur einen Bereich des Rasen.<br />
<br />
Folgende Parameter in der config.h beeinflussen die Aktivierung der Spirale:<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f //If mow motor Watt is over this value, it is assumed that the motor is under heavy load.<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f //If the mow moter is under heavy load, the measured watt must come under this value to reset heavy load.<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f //The mow motor is under load, if this Watt is measured.<br />
<br />
<br />
Die Implementierung der Aktivierung der Spirale befindet sich in der Datei: bCruise.h Klasse: class TCruisePerimeterNear: public Node<br />
<br />
Der Code für die Aktivierung ist folgendermaßen:<br />
if(CONF_ACTVATE_AUTO_SPIRAL) {<br />
(a) if(bb.mowMotorSensor.motorUnderHeavyLoad) {<br />
if(millis()-bb.lastTimeSpiralStarted > 60000ul) {<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
(b) if( (millis()-bb.lastTimeSpiralStarted > 180000ul) && bb.mowMotorSensor.checkIfUnderLoad() ) { // Alle 3 Minuten Spirale starten wenn motor belastet<br />
bb.flagCruiseSpiral = true;<br />
}<br />
}<br />
<br />
Es gibt zwei unabhängige Bedingungen, für das Aktivieren einer Spiralfahrt (a) und (b).<br />
<br />
(b) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.checkIfUnderLoad() true zurückgibt und die letzten 3 Minuten keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_LOAD 30.0f<br />
beeinflusst. Benötigt der Mähmotor mehr Leistung als CONF_MOW_MOT_UNDER_LOAD definiert, gibt die Funktion bb.mowMotorSensor.checkIfUnderLoad() true zurück ansonsten false.<br />
CONF_MOW_MOT_UNDER_LOAD beeinflusst auch "Langsamer fahren, wenn Mähmotor belastet" wie oben beschrieben.<br />
<br />
(a) Eine Spirale wird aktiviert, wenn bb.mowMotorSensor.motorUnderHeavyLoad() true zurückgibt und die letzten 60 Sekunden keine Spirale gefahren wurde. Die Berechnung in bb.mowMotorSensor.checkIfUnderLoad() wird durch die die Konstante<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON 45.0f<br />
#define CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF 30.0f<br />
beeinflusst. Zum bestimmen ob der Motor under heavy load ist, wird eine Hysterese verwendet. Sobald die Mähmotor Wattzahl über CONF_MOW_MOT_UNDER_HEAVY_LOAD_ON geht, gibt bb.mowMotorSensor.checkIfUnderHeavyLoad() true zurück. Doch erst wenn die Wattzahl wieder unter CONF_MOW_MOT_UNDER_HEAVY_LOAD_OFF geht wird false zurückgegeben.<br />
<br />
Die Funktionen checkIfUnderHeavyLoad () und checkIfUnderLoad () sind in der Datei: mowmotorSensor.h Klasse: class TMowMotorSensor : public Thread definert.<br />
<br />
Die Implementierung der Spirale selber befindet sich in der Datei: bCruise.h Klasse: class TCruiseSpiral: public Node<br />
<br />
folgende Werte beeinflussen das Fahren der Spirale:<br />
#define CONF_DISTANCE_BETWEEN_WHEELS_CM 36.0f // Distance where the wheels hits the ground do not measure on top of the wheels!!!<br />
#define CONF_MAX_SPIRAL_RADIUS_CM 150.0f<br />
#define CONF_START_SPIRAL_RADIUS_CM 27.0f<br />
#define CONF_SPIRAL_SEGMENTS 16.0f<br />
<br />
Anmerkung: Im BHT wird angezeigt, das die Spirale in der Klasse TCruiseMowMotHeavyLoad gestartet wird. Dies ist nicht der Fall, da die Implementierung sehr einfach ist. Die Klasse TCruiseMowMotHeavyLoad gibt es nicht. Die Funktion wurde in die Klasse TCruisePerimeterNear mit implementiert.<br />
<gallery><br />
File:RaindancerBHTSpiralfahrt.JPG | Spiralaktivierung designed im BHT<br />
</gallery><br />
<br />
==Perimeter Tracking==<br />
Hier wird der Perimetertrackingalgorithmus erklärt, mit dem Ziel genügend Informationen zu liefern, dass dieser durch den Anwender auf sein Chassis optimiert werden kann. Es fiel die Wahl auf diesen Algorithmus, da dieser unabhängig von der Perimeteramplitude ist. Weiterhin ist der Algorithmus extrem stabil und nicht von seinem Vorhaben abzubringen dem Perimeter zu folgen. [https://www.youtube.com/watch?v=RdufyzkYSPU '''Video Beispiel''']<br />
<br />
Als Perimetertrackingalgorithmus wird ein one bounce Algorithmus verwendet. Der Algorithmus fährt counter clockwise den Perimeter ab. Dabei bounced die rechte äußere Spule immer gegen den Perimeter von außen. Wenn diese gegen den Perimeter stößt, wird die Spule erstmal vom Perimeter abgestoßen. Danach bewegt sich die Spule in einem Bogen zum Perimeter hin. [https://www.youtube.com/watch?v=Y3wxURV0qtw '''Video Beispiel''']<br />
<br />
[[Datei:OneBounce.png]]<br />
<br />
Der Algorithmus ist in der Datei: bGotoAreaX.h Klasse: TlineFollow implementiert. <br />
Die folgende Darstellung zeigt die if Abfragen in einer anderen chronologischen Reihenfolge zur besseren Erklärung, als diese tatsächlich im Programmcode stehen. Daher nicht verwirren lassen, wenn man den Programmcode ansieht.<br />
<br />
Ablauf:<br />
Die rechte Spule befindet sich immer außerhalb des Perimeter.<br />
Wenn diese den Perimeter nach innen überschreitet, wird als erstes eine aggressive Drehung clockwise ausgeführt mit:<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 5));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed - 20)); <br />
<br />
Sollte die Spule dann nach 1 Sekunde nicht außerhalb sein, wird die Drehung aggressiver:<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 1sec inside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + 10)); <br />
bb.motor.R->setSpeed(-25); <br />
}<br />
<br />
Sollte die Spule dann nach 1,5sek Sekunde nicht außerhalb sein, wird gedreht<br />
if ((millis() - lastTransitionTime) > 1800) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECW;<br />
bb.motor.L->setSpeed(25);<br />
bb.motor.R->setSpeed(-25);<br />
}<br />
<br />
Wenn die Spule nun nach außen gedreht wurde, fährt der Roboter eine seichte Kurve counter clockwise, bis er den Perimeter erreicht.<br />
Für die Berechnung der Kurve, wird ein Integral verwendet, das mit dem Faktor Ki gesteuert werden kann.<br />
(Anmerkung: Das Integral wird auf 0 gesetzt, sobald die Spule den Perimeter überschreitet.)<br />
<br />
integral = integral + (Ki*error); // der Wert error ist eine Konstante und hat den Wert -1 wenn die Spule außerhalb des Perimeters ist.<br />
double Output = integral;<br />
<br />
Das Fahren der Kurver erfolg dann folgendermaßen: Dadurch, dass das Integral größer wird, wird die Kurve mit zunehmender Integralgröße kleiner.<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output)); // beachte: Output ist negative<br />
bb.motor.R->setSpeed((bb.cruiseSpeed));<br />
<br />
Wenn nach 1 Sekunde der Perimeter nicht überschritten wurde, wird aggressiver die Kurve gefahren;<br />
if ((millis() - lastTransitionTime) > 1000) { // If more than 2sec Outside rotate aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +5));<br />
}<br />
Wenn nach 1.5 Sekunde der Perimeter nicht überschritten wurde, wird noch aggressiver die Kurve gefahren:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
Wenn nach 2 Sekunde der Perimeter nicht überschritten wurde, wird gedreht:<br />
if ((millis() - lastTransitionTime) > 1500) { // If more than 2.8sec Outside rotate more aggressive<br />
bb.motor.L->setSpeed((bb.cruiseSpeed + Output));<br />
bb.motor.R->setSpeed((bb.cruiseSpeed +10));<br />
}<br />
if ((millis() - lastTransitionTime) > 2000) { // If more than 3.5sec Outside rotate full<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
}<br />
<br />
<br />
Sollte die linke Spule außerhalb des Perimeters sein, wird sofort counter clockwise gedreht:<br />
if (bb.perimeterSensoren.isLeftOutside() == true) {<br />
bb.cruiseSpeed = 25;<br />
bb.driveDirection = DD_ROTATECC;<br />
bb.motor.L->setSpeed(-25);<br />
bb.motor.R->setSpeed(25);<br />
waitForRightInside = true;<br />
}<br />
<br />
<br />
Zum Einstellen des Algorithmus sollte als erstes versucht werden eine gerade Strecke zu fahren. Dabei ist das erste Rausdrehen zu konfigurieren und Ki für den Bogen zum reinfahren.<br />
<br />
Testen des Algorithmus:<br />
Den Roboter auf den Perimeter stellen, so das die rechte Spule außen ist und die linke Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten. <br />
Der Befehl <br />
M<br />
stoppt den Test.<br />
<br />
Mit dem Befehl<br />
set.lfki,1.1<br />
kann der Ki Wert während des Testen eingestellt werden. Der Wert muss wenn zufriedenstellend ermittelt, in der Klasse TlineFollow im Konstructor zugewiesen werden. <br />
<br />
Wenn die Antriebsräder hinten sind, ist der Abstand zu den Spulen größer und die Spulen können außerhalb der Mitte angeordnet werden. Bei dem original Ardumower Chassis sind die Antriebsräder vorne. Hier muss die rechte Spule nah der Mitte angeordnet werden, ansonsten ist die Drehung zu asymmetrisch. Aufgrund der kurzen Distanz ist vermutlich auch das Bounce-Intervall von 1 Sek. zu verkürzen, so dass auf gerader Strecke vermutlich alle 0.3Sek gebounced werden muss.(aktuell nicht getestet)<br />
<br />
==Schnelle Rückkehr==<br />
Auf dem Rückweg zu Ladestation kann es sein, dass der Mower an einer Stelle auf das Perimeter fährt, so dass er den gesamten Perimeterdraht bis zur Ladestation abfahren muss. Um diesen Weg zu verkürzen, gibt es die schnelle Rückkehr.<br />
Der Anwender muss dazu das Perimeterkabel so verlegen, dass es ein Viereck ergibt. Diese Viereck wird dann vom Roboter beim Perimetertracking erkannt. Wenn er das Viereck erkannt hat, dreht er sich um 90 Grad vom Perimeter weg in den Innenbereich, und fährt auf die andere Seite des Rasens. Wenn er dort das Perimeterkabel entdeckt, nimmt er von dieser Stelle das Perimetertracking wieder auf.<br />
<br />
Um die schnelle Rückkehr zu aktivieren muss folgende Option in config.h gesetzt werden.<br />
#define CONF_DISABLE_FAST_RETURN false<br />
<br />
Für das Viereck hat sich folgende Abmessung als günstig herausgestellt. Es kommt allerdings auch auf die Abmessungen des Mowers an. Der Mower sollte bei dem Tracking in den Drehmodus kommen. Drehen bei der ersten Linkskurve. Dann drehen bei der nächsten Rechtskurve. Dann Linkskurve fahren. [Video:https://youtu.be/ipdVJzQn5Tc]<br />
<br />
Das Viereck kann auf zwei Arten verlegt werden. Einmal mit Ecken und einmal mit abgeflachten Ecken. Die Abgeflachten Ecken sind dazu da, dass der Mower an der Ecke besser erkennt, in welche Richtung er sich vom Perimeter wegdrehen soll, wenn er fast parallel zum Perimeter fährt. Dadurch ist die Perimeternahe Spule als erstes draußen und er dreht vom Perimeter weg anstatt zum Perimeter hin. Das ist notwendig, falls hinter dem Perimeter ein Beet kommt in das sich der Mower reindrehen könnte.<br />
<br />
[[Datei:ViereckSchnelleRückkehr.JPG]] <br />
<br />
[[Datei:ViereckSchnelleRückkehr2.JPG]] <br />
<br />
<gallery><br />
File:Raindancer FastReturn.png | Beispiel, wie ich meine Vierecke angebracht habe<br />
</gallery><br />
<br />
<br />
Die Erkennung ist abhängig von der Position der Spulen und vom Abstand der Spulen zum Antriebsrad.<br />
<br />
Die Implemetierung steht in der Datei: bPerimeterTracking.h Klasse: class TfindTriangle : public Node<br />
<br />
Die Erkennung erfolgt anhand des jeweils gedrehten Winkels. Sie wurde mit einer Statemachine umgesetzt.<br />
<br />
Den Ablauf der Statmachine und die berechneten Winkel kann man sich mit dem Befehl bht.tri anzeigen lassen.<br />
bht.tri <br />
<br />
Die entsprechenden Winkel und maximal Distanzen muss man dann im Code in der Klasse: class TfindTriangle anpassen.<br />
Im Folgenden die leicht ausgedünnte Klasse um einen besseren Überblick zu bekommen. Die Zeilen errorHandler.setInfoNoLog(..) sind die Ausgabe, wenn der Befehl bht.tri aktiviert wurde. Diese wurden hier mit aufgeführt um die Ausgabe besser interpretieren zu können.<br />
<br />
<br />
virtual NodeStatus onUpdate(Blackboard& bb) {<br />
...<br />
Der gefahrene Winkel wird vor dem Case Statement alle 500ms ermittelt.<br />
//============================================<br />
// Calculate driven angle every 500ms.<br />
//============================================<br />
if (millis() - lastRunAngleCalculation >= 500) {<br />
lastRunAngleCalculation = millis();<br />
... <br />
angle = (cmL - cmR) * 57.2957795f / CONF_DISTANCE_BETWEEN_WHEELS_CM;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfoNoLog(F("Winkel: %f cmL %f cmR %f\r\n"), angle, cmL, cmR);<br />
}<br />
}<br />
Abfrage der States<br />
// Check for left curve / right curve / second left curve<br />
switch (state)<br />
{<br />
<br />
Im case 0 wird nach eine Linkskurve gesucht. Ein negativer Winkel bedeutet eine Linkskurve/-drehung. Wenn der Winkel z.B. <-25 Grad ist, wurde diese gefunden und es wird in den case 1 geschaltet. <br />
case 0: // search for left curve<br />
if (angle < -25) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s0 set state = 1 Left turn found angle: %f ms: %lu\r\n"), angle, millis());<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 1; // Activate triangle searching<br />
}<br />
break;<br />
<br />
In case 1 wird ständig überprüft, ob eine bestimmte Strecke nach der Linkskurve überschritten wurde. Im Beispiel 55cm. Wenn ja, ist das zu weit und es wird wieder zurück in den case 0 gesprungen, da es nicht sein kann, das die erste Strecke so lang ist. Wenn innerhalb der Strecke von 55cm dann ein Winkel > 50 gefunden wurde, wird in den case 2 gesprungen. Ein positiver Winkel bedeutet eine Rechtskurve/-drehung. <br />
case 1: // search for right turn<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 55) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 0 distance %f > 55 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle > 50) { <br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s1 set state = 2 angle %f distance %f < 50\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 2;<br />
}<br />
break;<br />
<br />
In case 2 wird als erstes wieder die gefahrene Distanz nach dem Rechtswinkel überprüft. Solange die Distanz von 50 cm nicht überschritten wurde, wird auf eine Linkskurve geprüft. Wenn der Winkel <-25 Grad ist, wurde diese erkannt und es wird in den State 3 gesprungen. <br />
case 2: // search for second left curve<br />
distance = bb.motor.getDistanceInCMForTriangle();<br />
if (distance > 50) {<br />
state = 0;<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 0 distance %f > 50 ms: %lu\r\n"), distance, millis());<br />
}<br />
}<br />
else if (angle < -25) {<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s2 set state = 3 angle %f distance %f < -25\r\n"), angle, distance);<br />
}<br />
bb.motor.startDistanceMeasurementTriangle();<br />
...<br />
state = 3;<br />
}<br />
break;<br />
<br />
Case 3 gibt BH_SUCCESS an den BHT zurück und es wird auf die andere Seite des Rasens gefahren.<br />
case 3:<br />
if (flagShowFindTriangleStates) {<br />
errorHandler.setInfo(F("!03,s3 set state=0 Cross Lawn Activated\r\n"));<br />
}<br />
state = 0;<br />
return BH_SUCCESS;<br />
break;<br />
<br />
...<br />
}<br />
return BH_RUNNING;<br />
}<br />
<br />
<br />
Testen des Algorithmus: Den Roboter auf den Perimeter stellen, so das die linke Spule außen ist und die rechte Spule innen. Mit dem Befehl<br />
tpt //test perimeter tracking to dock. Mower stands on perimeter<br />
das Perimetertracking starten.<br />
<br />
Mit dem Befehl<br />
bht.tri <br />
die Ausgabe der Viereckserkennung starten. (tri steht für triangle, da vorher wurde ein Dreieck zur Erkennung verwendet wurde)<br />
<br />
==Mähzonen zwischen aneinander liegenden Flächen==<br />
Mähzonen können eingerichtet werden zwischen aneinander liegenden Flächen die eine direkte Verbindung haben. Dazu wird das Perimeterkabel zwischen den Flächen in einem Abstand von ca. 13cm verlegt. Es wird eine Lücke von ca. 30cm zu dem gegenüberliegenden Perimeterkabel gelassen. Dadurch ist die Wahrscheinlichkeit geringer, dass der Roboter auf die andere Fläche fährt.<br />
<br />
Siehe Bild:<br />
<gallery><br />
File:RaindancerGroundAreas.png | Beispiel, Mähzonenabgrenzung<br />
File:RaindancerZoneKabelverlegung.png | Abmessungen<br />
</gallery><br />
<br />
''(Im obigen Bild ist es normal nicht notwendig Mähzonen einzurichten, da der Roboter durch den Algorithmus relative gut alle Bereiche des Rasens abdeckt.)''<br />
<br />
Der Abstand des Bereichsabgrenzungskabels zum gegenüberliegenden Perimeterkabel (hier 30cm Abstand) kann durch Tests optimiert werden. Der Abstand hängt von der Funktionalität des Perimetertracking ab. Zum einen von der Position der linken Spule beim Tracken des gebenüberliegenden Kabels, sowie das Tracking des Bereichsabgrenzungskabels selber.<br />
<br />
In der config.h sollte die Konstante CONF_USE_ZONE_RECOGNITION auf true gesetzt werden.<br />
#define CONF_USE_ZONE_RECOGNITION true<br />
<br />
Da der Roboter voreingestellt mit den Spulen ca. 20cm über das Kabel fährt, kann es sein, dass er mit den Spulen dann innerhalb des nächsten Bereichs stehen bleibt. <br />
Wenn CONF_USE_ZONE_RECOGNITION false ist, würde der Roboter einfach weiterfahren, da er ggf. eine Ecke überfahren hat. <br />
Wenn CONF_USE_ZONE_RECOGNITION true ist, wird nach dem Überfahren geprüft, ob beide Spulen wieder innerhalb des Perimeters sind. Falls ja, wird mindestens eine Strecke von (-CONF_PERIMETER_DRIVE_BACK_CM-10) zurückgefahren. Also 10cm mehr als sonst CONF_PERIMETER_DRIVE_BACK_CM zurückfahren würde.<br />
<br />
Das Anfahren eines Bereiches aus der Ladestation heraus erfolgt mit dem Befehl:<br />
area,x //wobei x der zurückzulegende Weg in m ist.<br />
Wurde die angegebene Strecke x am Perimeter zurückgelegt, fängt der Mower an zu mähen.<br />
<br />
Die gefahrene Distanz auf dem Perimeter kann mit dem Befehl<br />
show.distance<br />
angezeigt bzw. gemessen werden.<br />
<br />
Achtung: Man sollte sich genau merken, wo die Kabel für die Mähzonenabgrenzung liegen für den Fall, dass der Rasen vertikutiert wird.<br />
<br />
==Verlegung des Perimeterkabels an Ecken==<br />
Der Mower bestimmt in welcher Richtung er sich am Perimter dreht anhand der zuerst rausgefahrenen Spule. Daher ist es wichtig die Ecken nicht im 90 Grad Winkel zu verlegen. <br />
Wenn der Mower z.B, mit der rechte Spule nahe am Perimeter langfährt und dann an der Ecke rausfährt, sollte auch die rechte Spule als erstes aus dem Perimeter fahren.<br />
<br />
In den folgenden Bildern sind drei Beispiele zu sehen, wie Ecken verlegt werden sollten.<br />
<br />
<gallery><br />
File:RaindancerCorner1.png | Außenecke<br />
File:RaindancerCorner2.png | Außenecke<br />
File:RaindancerCorner3.png | Innenecke<br />
</gallery><br />
<br />
==Temperatur Sensor==<br />
Es werden die Temperatursensoren DHT11/DHT21/DHT22/AM2301 unterstützt. Aktuell wurde aber nur mit dem Sensor DHT22 getestet.<br />
Der Temperatursensor wird mit dem dafür vorgesehenen Port des PCB1.3 verbunden. <br />
<br />
In config.h wird der verwendete Temperatursensor konfiguriert:<br />
#define DHTTYPE DHT22 <br />
<br />
Zum enablen des Services muss folgende Zeile konfiguriert werden:<br />
#define CONF_DISABLE_DHT_SERVICE false // Disables temp sensor<br />
<br />
Mit folgendem Befehl wird der Sensor ausgelesen: <br />
temp.show<br />
Im manuellen Mode wird der Sensor direkt ausgelesen. Es werden Temperatur, Luftfeuchtigkeit und die letzte gespeicherte Temperatur im Service angezeigt.<br />
Im auto mode wird nur die Temperatur die im Service gespeichert wurde angezeigt. Die Temperatur wird aktualisiert wenn der Mower über den Perimeter fährt und zum stehen kommt und mindestens 20 Sek. seit der letzten Messung vergangen sind.<br />
<br />
Der DHT Service schaltet den Strom des PCB1.3 ab, wenn eine Temperatur von 50 Grad zwei mal gemessen wurde:<br />
#define CONF_OVERHEATING_TEMP 50.0f // if this temperature is measured, robot shuts down the complete power for security<br />
<br />
==Shutdown Service==<br />
<br />
Wenn der shutdown service aktiviert wird, schaltet dieser den Strom über die Undervoltageprotection ab.<br />
Wenn ein Raspberry PI an den USB Port angeschlossen ist kann <br />
CONF_WAIT_FOR_PI_SHUTDOWN = true <br />
gesetzt werden.<br />
Dann wartet die Software 50 Sekunden bis zur Abschaltung. <br />
Es wird jede Sekunde $PwrOff und ein Countdown zu dem PI geschickt, so dass dieser herunterfahren kann.<br />
<br />
Mit dem Befehl:<br />
poweroff<br />
kann der shutdown über die Benutzerschnittstelle oder vom PI aus aktiviert werden.<br />
<br />
Der shutdown service wir auch von dem Batterie Service und dem Temperatur Service zum herunterfahren verwendet.<br />
Somit wird der PI informiert, dass er herunterfahren soll, wenn die Batteriespannung zu gering oder die Temperatur zu hoch ist.<br />
<br />
==GPS Service==<br />
Der GPS Service empfängt die Daten von dem GPS Modul. <br />
<br />
Es gibt zwei Möglichkeiten diese Daten zu verarbeiten. Beide Möglichkeiten können parallel genutzt werden.<br />
a) Die Empfangenen GPS Daten werden an das Raindancer Controlcenter weitergeleitet.<br />
b) Die Empfangenen GPS Daten werden in der Raindancer Firmware ausgewertet. Man kann dann einen Bereich auf der Rasenfläche definieren. <br />
Befindet sich der Mower in diesem Bereich wird angenommen, dass der Mower sich innerhalb der Perimeterschleife befindet. So besteht die Möglichkeit ein schwaches Perimetersignal auf größeren Flächen zu überbrücken.<br />
<br />
Das GPS Modul wird an den dafür vorgesehenen Anschluss an das PCB1.3 angschlossen. Das GPS Modul sendet periodisch Daten an das PCB1.3.<br />
Falls keine Daten empfangen werden, bitte folgenden Artikel lesen. Es kann sein, dass RX3 und TX3 auf dem PCB1.3 falsch verdrahtet wurden.<br />
https://www.ardumower.de/index.php/de/forum/navigation-gps-odmetrie/1737-wait-for-gps-position-data<br />
<br />
===Senden an das Raindancer Controlcenter===<br />
Zum aktivieren des GPS Services muss folgendes konfiguriert werden:<br />
#define CONF_DISABLE_GPS false<br />
<br />
Für die erste Inbetriebnahme kann man folgende Parameter setzen:<br />
#define CONF_GPS_PASS_THROUGH true<br />
#define CONF_DEACTIVATE_GPS_CALCULATION true<br />
Der Parameter #define CONF_GPS_PASS_THROUGH sagt der Firmware, dass alle empfangenen GPS Daten zum Controlcenter geschickt werden sollen.<br />
<br />
<br />
Damit man diese Daten auf der Console angezeigt bekommt, muss folgender Befehl ausgeführt werden:<br />
set.cco,1<br />
Nun sieht man alle Daten die an das Controlcenter geschickt werden. Darunter auch die GPS Datensätze.<br />
<br />
Mit folgendem Befehl stoppt man die Ausgabe:<br />
set.cco,0<br />
<br />
<br />
<br />
Standardmäßig schickt das GPS Modul mehrere Datensätze in einem 1 Sekunden Intervall. Diese Datensätze werden nicht alle benötigt und erzeugen einen Overhead.<br />
Es wird nur der Datensatz: $GPRMC bei NEO-6M und $GNRMC bei NEO-M8N benötigt.<br />
Daher gibt es die Möglichkeit, das Modul bei dem Starten der Raindancer Firmware so einzustellen, das es nur den benötigten Datensatz schickt und dies auch nur in einem 3 Sekunden Takt.<br />
Dazu wird folgender Parameter eingestellt:<br />
#define CONF_INIT_GPS_WITH_UBLOX true<br />
Damit wird beim Hochfahren das Array const char UBLOX_INIT[] (steht in config.h) an das GPS Modul geschickt. Zum aktivieren bzw. deaktivieren muss man dann einzelne Zeilen ein- bzw. auskommentieren.<br />
<br />
===Aktivieren der internen Berechnung===<br />
Auch hier sollte #define CONF_INIT_GPS_WITH_UBLOX true verwendet werden.<br />
Zum aktivieren der internen Berechnung muss <br />
#define CONF_DEACTIVATE_GPS_CALCULATION false<br />
gesetzt werden.<br />
Bei dem NEO-6M Modul wird der Datensatz: $GPRMC verwendet. Bei dem NEO-M8N wird der Datensatz $GNRMC verwendet.<br />
Daher müssen je nach verwendetem Modul folgende Zeilen ein bzw. auskommentiert werden:<br />
#define CONF_N_GPRMC_STR "$GPRMC" // GPS messagetype begin for $GPRMC for NEO-6M<br />
//#define CONF_N_GPRMC_STR "$GNRMC" // GPS messagetype begin for $GPRMC for NEO-M8N<br />
<br />
Mit <br />
gps.show<br />
kann man sich die berechneten Werte anzeigen lassen.<br />
<br />
Falls man in UBLOX_INIT[] den Datensatz "GxGGA on" mit eingebunden hat, werden zusätzlich noch Quality, Satellites und Altitude angezeig. Diese werden aber nicht weiter verwendet.<br />
<br />
<br />
Es besteht die Möglichkeit einen GPS Bereich zu Konfigurieren, in dem der Mower annimmt er ist im Perimeter falls hier das Perimetersignal für die Erkennung zu schwach ist.<br />
<br />
Der Bereich wird als Polygon angegeben.<br />
const float CONF_LAT_POLYGON_Y[] = { 54.083245f, 54.084068f, 54.084679f, 54.085623f, 54.084018f }; // Latitude polygon points<br />
const float CONF_LON_POLYGON_X[] = { 10.447986f, 10.447055f, 10.446015f, 10.447120f, 10.44930f }; // Longitudinal polygon points<br />
const int CONF_NUMBER_OF_POLYGON_POINTS = 5; // The number of the ploygon points<br />
Jede Spalte gehört zu einem Polygonpunkt. Man kann in https://www.google.de/maps z.B. einen Punkt in die Suche eingeben: 54.08728,10.448400. Dann sieht man wo diese Koordinate ist. So kann man dann punkt für punkt sehen, wie das Polygon aufgebaut ist. <br />
Wichtig ist, dass mit CONF_NUMBER_OF_POLYGON_POINTS die Anzahl der Spalten richtig definiert ist. Es können 3 bis N Koordinatenpunkte eingegeben werden. Allerdings schlage ich vor nicht mehr als 8 Punkte zu verwenden, um die Berechnungszeit so gering wie möglich zu machen.<br />
<br />
Um die Punkte zu ermitteln, kann man den Roboter an den entsprechenden Punkt stellen und gps.show eingeben. Dann wird z.B. folgendes angezeigt:<br />
!03,$GPRMC,104503.00,A,5123.24690,N,00812.92063,E,0.094,,290718,,,A*72<br />
!03,$GPRMC speed: 0.094000 course:0.000000<br />
!03,$GPRMC lat: 54.08744800,N lon: 10.44867700,E<br />
!03,$GPRMC date: 29.7.18 time: 11:45:3<br />
<br />
Der Punkt kann dann aus der Zeile !03,$GPRMC lat: 53.08744800,N lon: 9.44867700,E entnommen werden. Hier für Latitude = 54.087448 und Longitude=10.448677.<br />
<br />
<br />
Die Bereichserkennung wird mit <br />
#define CONF_USE_GPS_POLYGON true<br />
eingeschaltet.<br />
<br />
Es ist zu beachten, dass das GPS Signal eine toleranz von +-10m hat. D.h. man sollte weit genug vom Perimeter weg bleiben. Da das manchmal nicht geht, wurde noch der Parameter <br />
#define CONF_PER_THRESHOLD_IGNORE_GPS 300<br />
eingeführt. Dieser besagt, dass wenn die Amplitude vom Perimeter diesen Wert überschreitet, wird auf jeden Fall das Perimetersignal verwendet und nicht mehr durch das GPS Signal überschrieben, auch wenn der Mower im GPS Bereich ist.<br />
Der Wert 300 muss entsprechend den eigenen Anforderungen eingestellt werden.<br />
<br />
[[File:warning.png]]'''Sicherheitshinweis: Falls das Perimetersignal ausfällt und der GPS Bereich den Perimeter überschreitet, wird der Mower den Perimeterbereich verlassen'''<br />
<br />
=Perimeter Sender=<br />
Es wird die original Ardumower Sender Hardware verwendet. Die Software wurde etwas abgeändert. Es wird ein 128 Bit Signal gesendet.<br />
<br />
Folgendes Perimetersignal wird gesendet:<br />
1, 1, -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1,<br />
-1, 1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, -1, -1, 1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, 1, 1, -1, -1, 1<br />
<br />
Die LEDs haben folgende Funktion (von links nach rechts):<br />
*1. 12V vorhanden<br />
*2. 5V vorhanden<br />
*3. Grün wenn der Interrupt läuft, der das Signal sendet ( rote LED nicht verfügbar). Aus wenn geladen wird.<br />
*4. Grün wenn ein Strom durch den Perimeter fließt, rot wenn keine Strom fließt (Perimeter unterbrochen) oder sehr wenig Strom. Aus wenn geladen wird.<br />
*5. Gelb der Roboter wird geladen. Perimetersignal ist ausgeschaltet.<br />
<br />
Achtung: die LEDs 3 und 4 sind Duo LEDs. D.h. diese haben zwei Farben. Bei LED 3. ist die rote LED nicht ansprechbar, da auf dem Nano der falsche Pin hardwaretechnisch connected wurde. Desweiteren, können die LEDs falsch herum eingelötet worden sein. Dann wundert man sich z.B., dass LED 4. rot ist obwohl alles in Ordnug ist und ein Strom fließt. Oder eben LED 3. rot anzeigt, obwohl ich hier grün geschrieben habe.<br />
<br />
'''Wenn der Sender an ist und der Roboter kehrt nach zwölf Stunden nicht in die Ladestation, schaltet der Sender das Signal ab.''' Dann entweder den Sender neu starten, oder den Roboter in der Ladestation laden.<br />
<br />
=Ladestation=<br />
Die Ladestationen werden gegen den Uhrzeigersinn angefahren.<br />
<br />
Wird keine Ladestation verwendet, sollte<br />
CONF_DISABLE_CHARGINGSTATION = true <br />
eingestellt werden. Dann fährt der Mower bei geringer Batteriespannung zum Perimeter und bleibt stehen.<br />
<br />
==Kopfladestation==<br />
<br />
Wird eine Kopfladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 3 cm nachgeben können wenn der Mower dagegen fährt. Besser wären 4 cm. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Kopfladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION false //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION true //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,0<br />
eingeben. Der Mower fährt dann 1m rückwärts, dreht um 90 Grad und fährt 50cm vorwärst. Dreht dann nochmal einen Zufallswinkel und fängt an zu mähen. Dieser Prozess läuft ohne Bumperschutz ab. Daher ist darauf zu achten, dass dieser Bereich frei von Hindernissen ist.<br />
<br />
Mit folgenden Parametern können die Fahrtstrecken konfiguriert werden:<br />
#define CONF_HEAD_CHARGING_DRIVE_BACK_CM 100 //when the mower leaving the head charging station, how far it should drive back<br />
#define CONF_HEAD_CHARGING_DRIVE_FORW_CM 50 //when the mower drove back and then rotates 90 degree, how far it should run forward that both coils securely inside<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 3cm zurück und 3 cm vor.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
==Durchgangsladestation==<br />
Wird eine Durchgangsladestation verwendet ist darauf zu achten , dass die Kontakte mindestens 10cm schleifen können. Weiterhin ist zu beachten, dass der Anpressdruck der Kontaket ausreichend ist.<br />
<br />
Um eine Durchgangsladestation zu verwenden muss in config.h folgendes konfiguriert werden:<br />
#define CONF_DISABLE_CHARGINGSTATION false<br />
#define CONF_PASS_THROUGH_CHARGING_STATION true //the mower can go through the station<br />
#define CONF_HEAD_CHARGING_STATION false //the mower can't go through the station<br />
<br />
Mit dem Befehl<br />
gohome<br />
wird der Mower beim Mähen angewiesen den Perimeterdrath zu suchen und in die Ladestation zu fahren.<br />
<br />
Zum Testen kann der Mower 2m vor der Ladestation auf den Perimeterdraht plaziert werden. Dann<br />
tpt<br />
eingeben. Der Mower fährt dann zu Ladestation.<br />
<br />
Zum verlassen der Ladestation <br />
area,10<br />
eingeben. Der Mower fährt dann 10m am Perimeter draht entlang und fängt dann an zu mähen. 10m kann gegen eine beliebige Entfernung ausgetauscht werden.<br />
<br />
<br />
Wenn der Mower die Ladekontakte erkannt hat, fährt er 4cm vorwärts, 3cm zurück und 3 cm vor. Dies dient dazu die Kontakte leicht zu schleifen für einen besseren Kontakt.<br />
Dann wird das Laderelay eingeschaltet. Nach 10 Sekunden wird überprüft, ob ein Ladestrom fließt. Falls nicht, wird das Andocken ein zweites mal versucht. Wenn dies nicht funktioniert, wird ein Fehler ausgegeben.<br />
<br />
=Troubleshooting=<br />
==Mower bleibt stehen==<br />
[[Problem:]]<br />
Mower blieb stehen, Ursache war wohl der Sender. Da leuchteten nur <br />
noch die beiden linken LEDs. Sender ausgeschaltet und wieder <br />
eingeschaltet, 4 LEDs wieder auf grün und dann ging es wieder.<br />
<br />
[[Lösungsvorschlag:]]<br />
Die dritte grüne Leuchte von links zeigt an, ob der Sender Interrupt im Nano läuft. <br />
<br />
Möglichkeit a)<br />
Der Sender ist länger als 12h an, ohne das der Roboter wieder in die Station zurückgekehrt ist. Dann schaltet der Sender das Perimetersignal ab.<br />
<br />
Möglichkeit b)<br />
Da diese nicht an war scheint sich der Nano aufgehängt zu haben. Falls das noch mal passiert, würde ich den China Nano gegen einen original Arduino Nano austauschen. Da die Software bei mir seit einem Jahr läuft, gehe ich '''nicht''' davon aus, das diese die Ursache ist. Ich hatte vorher billige Nanos verwendet. Die waren bei mir nicht wirklich Frequenzstabil, was für den Sender aber notwendig ist. Nun habe ich einen Originalen drin.<br />
<br />
==Ich bekomme diese Meldung: Out: READ und In: CMD==<br />
[[Problem:]] In Arduino Central wird folgendes angezeigt:<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
In: CMD: Command not recognized.<br />
Out: READ<br />
[[Lösungsvorschlag:]]<br />
In den Arduino Central Settings ist "Read Command -> Enable Read Command" eingeschaltet<br />
<br />
=Understanding the Behaviour Tree=<br />
<br />
Die Beschreibung steht ausschließlich in Englisch zur Verfügung.<br />
<br />
#REDIRECT [[Understanding the Behaviour Tree]]</div>Roland