Arduino Forum

Topics => Device Hacking => Topic started by: Dawiinci on Apr 13, 2014, 07:02 pm

Title: Controlling Automower
Post by: Dawiinci on Apr 13, 2014, 07:02 pm
I have an Automower 220 AC which I want to control with the Arduino Yun. There are people who have done this already with other system and it works.

However once I connect the Yun to the Automower it doesn't work. I'm not sure if I messed up the connection or the sketch. Except the temperature and humidity I don't get any feedback. So I assume there is something wrong with the serial connection. (maybe in doCommand)

Attached you'll find my sketch, and some information about the connection.

I have the information from here:
http://homematic-forum.de/forum/viewtopic.php?t=7295

Thanks for any help in advance!
Title: Re: Controlling Automower
Post by: Dawiinci on Apr 20, 2014, 12:04 pm
Can someone please confirm if the serial code should work?

Thanks
Title: Re: Controlling Automower
Post by: pylon on May 07, 2014, 04:59 pm
Don't you think you should start with an easier sketch? One that just does the serial communication with your mower?

The Serial object is the virtual serial interface on the USB bus. If you want to use the hardware serial interface on pin 0 and 1, use the Serial1 object.
Title: Re: Controlling Automower
Post by: Dawiinci on May 07, 2014, 07:24 pm
Thanks for your help I really appreciate it!

The problem is I need to have it connected via Wifi since a cable connection is not possible. But I have some experience with the modified bridge sketch in another project which works pretty well.

In short words I can't send any "serial" code without the bridge sketch. As far as I understand I can't use USB and Pin0/Pin1 anyway.

Since the Automower has no advanced protocol I have just to send the HEX code and listen to the answer. In theory pretty simple.

1 Get command to do something
2 Send HEX code through TTL
3 wait and listen to answer on TTL
4 store HEX code to send it back to the request over HTTP

Problem seems to be in step 2 and 3.
Title: Re: Controlling Automower
Post by: pylon on May 07, 2014, 07:51 pm
Quote
In short words I can't send any "serial" code without the bridge sketch. As far as I understand I can't use USB and Pin0/Pin1 anyway.


I understand that in the final application you have to use the WiFi for the communication. But I would try to communicate with the mower over simple serial communication first and when this works advance to the WiFi connection.

Why can't you use USB? You cannot use the hardware serial interface and the Bridge class at the same time, that's correct.

To be prepared for the WiFi usage later, you can start using the AltSoftSerial library (https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html (https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html)) to get a software emulation of a serial interface and one that is not blocking the complete Arduino. The pins are fixed to 13 and 5. You'll loose your LED but you can use any other pin to light an LED.
Title: Re: Controlling Automower
Post by: Dawiinci on May 07, 2014, 08:17 pm
I did the other way - the bridge (Wifi and HTTP) works but the serial connection doesn't. The problem is I can't really take the robot inside to test this and I don't want to take the computer outside.

Maybe I don't understand some restrictions from the bridge sketch and serial over Pin1/Pin0:
Quote
... You cannot use the hardware serial interface and the Bridge class at the same time, that's correct.
Title: Re: Controlling Automower
Post by: pylon on May 07, 2014, 08:56 pm
Quote
Maybe I don't understand some restrictions from the bridge sketch and serial over Pin1/Pin0:


The hardware serial interface is used to communicate between the two processors the Yun has, on the AVR-side (the Arduino sketch) the Bridge class is responsible for this.

How did you connect the mower to the Arduino? Please don't post the same pictures again, I want to see how you did it.
Title: Re: Controlling Automower
Post by: Dawiinci on May 10, 2014, 10:17 am
OK, here are some pictures (front, back and connector to Automower) including a short description.

470 uF 35 V capacitor
Spark Fun Logic Level Converter
serial (HV) connected to 1 and 0 on the Arduino
power connected to 5V  and GND
don't mind the blue sensor brick

Thanks!
Title: Re: Controlling Automower
Post by: pylon on May 12, 2014, 11:37 am
Quote
serial (HV) connected to 1 and 0 on the Arduino


This probably won't work because the hardware serial interface (which is on pin 0 and 1) is used for inter-processor communication on the Yun. If you have pins 5 and 13 in the Yun unconnected, use the AltSoftSerial library (https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html (https://www.pjrc.com/teensy/td_libs_AltSoftSerial.html)) to get a software emulated serial interface.

Quote
power connected to 5V  and GND


Your schematics say 3V3 and not 5V for the mower.

How do the wires connect to the mower?
Title: Re: Controlling Automower
Post by: Dawiinci on May 12, 2014, 01:07 pm
Automower powers the Yun with 5V and also delivers 3.3V for serial.

I will have a look at the library. Thanks.
Title: Re: Controlling Automower
Post by: Dawiinci on May 12, 2014, 07:41 pm
I replaced the hardware serial part in my sketch with SoftwareSerial:

Code: [Select]
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 7); // RX, TX


replaced in void setup()
Code: [Select]
  Serial.begin(9600);
with
Code: [Select]
  mySerial.begin(9600);


and added in void loop()
Code: [Select]
 if (mySerial.available())
   Serial.write(mySerial.read());
 if (Serial.available())
   mySerial.write(Serial.read());


and of course changed the communication
Code: [Select]
// Send
mySerial.write(commandAutomower, 5);

// Receive
delay (1000);
if (mySerial.available() >= 5)
{
  mySerial.readBytes(statusAutomower, 5);
}


However I'm not sure if I should replace    
Code: [Select]
mySerial.readBytes(statusAutomower, 5);
with
Code: [Select]
mySerial.read(statusAutomower, 5);


I couldn't test it yet but are there any concerns  about these changes?


Title: Re: Controlling Automower
Post by: pylon on May 13, 2014, 11:49 am
Code: [Select]
mySerial.read(statusAutomower, 5);

There is no read() method that takes two arguments. This won't work.

Why don't you use AltSoftSerial but SoftwareSerial? The later will make you much more trouble because it blocks interrupts during every transfer and consumes all processing power available. So you might have to slow down the controlling application on the PC to not overflow the incoming serial hardware doing the Bridge transfer. The SoftwareSerial will block interrupts for at least 1ms (1 byte) during which the Bridge interface might transfer up to 25 bytes, 24 of them might magically disappear because no interrupt handler is emptying the hardware register.
Title: Re: Controlling Automower
Post by: Dawiinci on May 13, 2014, 04:51 pm
Makes sense to use AltSoftSerial you are right.

I receive 5 bytes and I assumed it will put it into the array of the size 5.
But I have to go through this code again.
Title: Re: Controlling Automower
Post by: Dawiinci on May 13, 2014, 07:37 pm
Ok, I changed it to AltSoftSerial. First I thought it would be better to use something that is already included.

Code: [Select]
#include <AltSoftSerial.h>
AltSoftSerial altSerial;


Code: [Select]
void setup() {
...
  altSerial.begin(9600);
}

/
Code: [Select]
/ Send
altSerial.write(commandAutomower);

// Receive
delay (1000);
if (altSerial.available() >= 5)
{
  altSerial.read(statusAutomower);
}


I'm not sure about the following:
1) Pin5 and Pin13 apply for the Yun as well? In that case I can't use the internal LED anymore?
2) commandAutomower is an array with 5 bytes (HEX). Will altSerial.write(commandAutomower, 5); send out these 5 bytes in order without any LF CR or something like this? Does write even work?
3) Will altSerial.read(statusAutomower); read only the next 5 bytes? What happens if there are only four or six?
4) If I wait 1000 ms before reading (to give the Automower time to respond), will it be buffered or is it better not to wait?

Thanks again!



edit:
I get this error message
Quote
Automower.ino: In function 'void doCommand(YunClient)':
Automower:157: error: no matching function for call to 'AltSoftSerial::read(uint8_t [5])'
/Arduino/libraries/AltSoftSerial/AltSoftSerial.h:44: note: candidates are: virtual int AltSoftSerial::read()
Title: Re: Controlling Automower
Post by: pylon on May 13, 2014, 09:10 pm
Code: [Select]
Automower.ino: In function 'void doCommand(YunClient)':
Automower:157: error: no matching function for call to 'AltSoftSerial::read(uint8_t [5])'
/Arduino/libraries/AltSoftSerial/AltSoftSerial.h:44: note: candidates are: virtual int AltSoftSerial::read()


Use your old readBytes method, as I already wrote, there is no read method that reads multiple bytes.

Quote
1) Pin5 and Pin13 apply for the Yun as well? In that case I can't use the internal LED anymore?


Yes.

Quote
2) commandAutomower is an array with 5 bytes (HEX). Will altSerial.write(commandAutomower, 5); send out these 5 bytes in order without any LF CR or something like this? Does write even work?


It will send these 5 bytes (bytes are not in hex although they may be printed in hex) over the emulated serial interface. Yes, write works.

Quote
3) Will altSerial.read(statusAutomower); read only the next 5 bytes? What happens if there are only four or six?


It will do nothing except generating a compiler error. See above.

Quote
4) If I wait 1000 ms before reading (to give the Automower time to respond), will it be buffered or is it better not to wait?


If wait means you're calling delay() it's always better not to do that if anything else should happen on your Arduino (as receiving characters from any interface). Although most of this stuff is handled in the background using interrupts, these handlers just copy the incoming stuff to buffers and these buffers may overrun. Try to always react on events and never wait for fixed times except you have no other option.
Title: Re: Controlling Automower
Post by: Dawiinci on May 14, 2014, 02:09 pm
Thanks. So with readBytes I can use two arguments?
I think with available >= 5 it should limit it to 5 bytes already, right?

I removed the delay. But is there a timeout if the response isn't immediate?
Should I move the reading to the loop?
BTW. There won't be any data except after sending 5 bytes.
Title: Re: Controlling Automower
Post by: pylon on May 15, 2014, 04:04 pm
Quote
So with readBytes I can use two arguments?


Yes.

Quote
I think with available >= 5 it should limit it to 5 bytes already, right?


You don't need that because readBytes() already waits until either the number of bytes were received or a configurable timeout was reached.

Quote
But is there a timeout if the response isn't immediate?


If you use readBytes() there may be one. See http://arduino.cc/en/Reference/Stream (http://arduino.cc/en/Reference/Stream)

Quote
Should I move the reading to the loop?


Please explain in more detail.

Quote
There won't be any data except after sending 5 bytes.


What does that mean?
Title: Re: Controlling Automower
Post by: Dawiinci on May 15, 2014, 06:40 pm
Thanks this is really helpful.

So I have a standard Timeout of 1000 ms which I can even extend by using altSerial.setTimeout(2000). The idea with the loop was to get data even after a timeout but because I can change it this became obsolete.

To clarify the last cryptic sentence:
I have to send exactly 5 bytes to get exactly 5 bytes back - no control bytes or something similar
If I don't send these 5 bytes there is nothing to read.
This means after timeout the received bytes are reset. This is helpful if only four bytes would be read. In this case the next status report will be a fresh 5 byte package.

But maybe I'm thinking too complex with this one. ;)

Again thanks a lot, there might be some questions when I can use the hardware to test it.
Title: Re: Controlling Automower
Post by: Dawiinci on May 17, 2014, 10:56 pm
I finally tested it on the real hardware. It works to send commands, but I don't get the right feedback.

The status codes should look like this:
   6, 12, 18, 1000, etc.
Unfortunately I don't know how the hex code looks like and of course my script doesn't match these and gives unknown status.
If I emulate the response 0xFF 0xFF returns me -1.

Also the return of the command which should be the same as the command doesn't match.
Code: [Select]
if(memcmp(statusAutomower, commandAutomower, 5) == 0)
{
  client.print("done");
}
else
{
  client.print("failed");
}


I think there is something wrong with my conversion of the response to a number.

Code: [Select]
int statusInt = statusAutomower[3] << 8 | statusAutomower[4];
       client.print(statusInt);
Title: Re: Controlling Automower
Post by: Dawiinci on May 18, 2014, 11:25 am
This might help (from the Automower project):

Code: [Select]
#Ermitteln, ob es sich um einen Read oder Write Befehl handelt
if {([string range $hexin 2 2] == "8" || [string range $hexin 2 2] == "9" ||[string range $hexin 2 2] == "A" ||[string range $hexin 2 2] == "B" ||[string range $hexin 2 2] == "C" ||[string range $hexin 2 2] == "D" ||[string range $hexin 2 2] == "E" ||[string range $hexin 2 2] == "F")} {
#Write: Prüfen, ob Byte 1-5 (Byte 4 und 5 vertauscht) der Rückgabe vom Automower mit den Input-Bytes übereinstimmen
if {([string range $hexout 0 5] == [string range $hexin 0 5]) && ([string range $hexout 8 9] == [string range $hexin 6 7]) && ([string range $hexout 6 7] == [string range $hexin 8 9])} {
#Byte 4 und 4 tauschen und als Dezimalwert zurückgeben
set final_result [expr 0x[concat [string range $hexout 8 9][string range $hexout 6 7]]]
} else {
set result_string "#[clock format [clock sec] -format %H:%M:%S]:Write-Error /$command"
if {$debug_mode != 0} {Write_Logfile "[clock format [clock sec] -format %H:%M:%S]: Write-Error (IN= $hexin / OUT= $hexout)" "a"}
}
} else {
#Read: Prüfen, ob Byte 1-3 der Rückgabe vom Automower mit den Input-Bytes übereinstimmen
if {[string range $hexout 0 5] == [string range $hexin 0 5]} {
#Byte 4 und 4 tauschen und als Dezimalwert zurückgeben
set final_result [expr 0x[concat [string range $hexout 8 9][string range $hexout 6 7]]]
} else {
set result_string "#[clock format [clock sec] -format %H:%M:%S]:Read-Error /$command"
if {$debug_mode != 0} {Write_Logfile "[clock format [clock sec] -format %H:%M:%S]: Read-Error (IN=$hexin / OUT=$hexout)" "a"}
}
}

I just need to do this with Arduino.
Title: Re: Controlling Automower
Post by: pylon on May 19, 2014, 06:33 pm
I would start by returning the hex codes of the mower's answer to the Yun client:

Code: [Select]
for (uint8_t e = 0; e < 5; e++) {
  client.print(statusAutomower[e], HEX);
  client.print(" ");
}


Post that output.

The basic code you posted seems to do something different than your code, so at least that very short excerpt doesn't help a lot.
Title: Re: Controlling Automower
Post by: Dawiinci on May 25, 2014, 07:53 pm
Thanks for the hints. I managed to get the status correctly.

However after some time (typically hours) I get weird messages:

Instead of 56 I get 14392
14392 is 0x3838 which looks a bit like the command itself:
  uint8_t timeAutomower[5] = { 0x0F, 0x00, 0x38, 0x00, 0x00 };

I assume it takes the wrong bytes, maybe the Automower repeated himself or missed to send a byte. Therefore the read 5 bytes doesn't start with an 0x0F anymore. I have no idea just guessing.

How can I implement something that checks if the start bit is correct?

After I reload the sketch over wifi it works again but this is not an optimal way. Can the Arduino can restart itself with a command?
Title: Re: Controlling Automower
Post by: pylon on May 27, 2014, 06:22 pm
Quote
However after some time (typically hours) I get weird messages:


Sounds like you're running out of memory slowly. Get rid of the usage of the String class. Although the worst memory leaking bug was fixed in version 1.0.5 of the IDE it still makes excessive use of dynamic memory allocation which fragments the memory and at some point it cannot allocate enough memory. At that point things get weird and unpredictable. Convert the complete string handling to C strings (character arrays).

Also use the F() macro for all constant string calls to print() and println() methods.

Quote
How can I implement something that checks if the start bit is correct?


You can parse the message and react on each byte instead of reading 5 bytes and checking for complete combinations. Although if the mower is only sending data if you sent a command before, this shouldn't be necessary.
Title: Re: Controlling Automower
Post by: Dawiinci on May 28, 2014, 03:04 pm
Makes sense.

Do you have  examples? I don't understand what you mean.

Code: [Select]
   int messwert = statusAutomower[4] << 8 | statusAutomower[3];

Code: [Select]
  String command = client.readStringUntil('/');
 
Code: [Select]
client.print("Stop");
What do I have to replace with what?

Thanks
Title: Re: Controlling Automower
Post by: pylon on May 30, 2014, 03:12 pm
Code: [Select]
client.print("Stop");

gets

Code: [Select]
client.print(F("Stop"));

and

Code: [Select]
String command = client.readStringUntil('/');

maybe written as

Code: [Select]
#define BUFFERSIZE 40
uint8_t buffer[BUFFERSIZE];
uint8_t i = 0;
while (i < BUFFERSIZE) {
  if (client.available()) {
    uint8_t c = client.read();
    if (c == '/') break;
    buffer[i++] = c;
  }
}


you can then use strncmp() to compare the string to a fixed String and there is also a strncmp_P() version to hold the compare string in flash only and save some RAM. This code misses a timeout handling and other error handling (what if buffer overflows?).
Title: Re: Controlling Automower
Post by: Dawiinci on May 31, 2014, 05:25 pm
Thanks a lot. I replaced the print with F(). The other command was used in the bridge example and I use it in another sketch as well without issues. Now I have to test it.

Do you expect issues withe the compare functions I use?
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 02, 2014, 09:12 pm
Unfortunately still having the same issue.

Status returns 14392 instead of 56.

Since   
Code: [Select]
String command = client.readStringUntil('/');
is also in other scripts that work, I have no clue what to do now. If I reprogram the Arduino with the same sketch it works normally for some time. Probably a simple restart would fix this issue.

Btw. is there a code way to restart the sketch? (at least this will keep the device working until I found the error)
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 03, 2014, 07:15 pm
Today it happened again, at the same time I didn't have network connection to the device and after this I had this weird feedback. So it might be the cause or a side effect of this. Maybe the cause is even alt.Serial...?
Title: Re: Controlling Automower
Post by: pylon on Jun 04, 2014, 05:53 pm
Quote
The other command was used in the bridge example and I use it in another sketch as well without issues.


That was the case with the print() calls without the F() macro too. Just because it works for some time doesn't mean that it cannot be responsible for the problems after running a while. You're using the String class and that class fragments the available memory after some time. Once there isn't enough memory to fulfill the next allocation request, the program starts to react unpredictably.

Quote
Status returns 14392 instead of 56.


Provide the whole 5 bytes of output (best is to post it in hexadecimal format) not just a single part of it.

Also please post the current code you're working with, I guess you changed some stuff in the meantime.

Quote
Btw. is there a code way to restart the sketch?


Sure there is, but you should get the code to run reliably and not to restart it every other second.

Quote
Do you expect issues withe the compare functions I use?


Do you mean the "memcmp()" function? No, that works very well.
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 11, 2014, 07:56 pm
Thanks a lot, I attached my latest code (except the changes described in this post).
This worked for many days but failed suddenly like before. So I think you are right and I have to change those parts.

I understand to replace this line
Code: [Select]
String command = client.readStringUntil('/');

with this code:
Code: [Select]
#define BUFFERSIZE 40
uint8_t buffer[BUFFERSIZE];
uint8_t i = 0;
while (i < BUFFERSIZE) {
 if (client.available()) {
   uint8_t c = client.read();
   if (c == '/') break;
   buffer[i++] = c;
 }
}


Then I changed this:
Code: [Select]
 if (command == "digital") {

to:
Code: [Select]
if (strcmp (buffer, "digital") == 0)



But this doesn't compile anymore.
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 12, 2014, 09:51 am
Problem happens if Automower has low battery. So I have to restart Arduino because it is probably not an issue of the code. How can I do this?
Title: Re: Controlling Automower
Post by: pylon on Jun 12, 2014, 03:06 pm
Change

Code: [Select]
if (strcmp (buffer, "digital") == 0)

to

Code: [Select]
if (strcmp ((char *)buffer, "digital") == 0)

and it compiles for me.

Quote
Problem happens if Automower has low battery. So I have to restart Arduino because it is probably not an issue of the code. How can I do this?


What happens if the mower is low on battery? Does the voltage that powers the Arduino drop? How much voltage do you have with a full battery? How much if it's getting empty? Where do you feed the Arduino with this voltage (Vin, 5V, power connector)?

You can restart the Arduino by pushing the reset button. You probably meant how to do it in software: that doesn't make sense because your software is already not running correctly, so don't expect it to reset itself.
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 12, 2014, 03:20 pm
I can read the Sensors so the issue might be in the Automower side.

But I will try your code thanks.
Title: Re: Controlling Automower
Post by: pylon on Jun 12, 2014, 05:56 pm
Quote
I can read the Sensors so the issue might be in the Automower side.


Why do you want to restart the Arduino then? What do you expect that this should fix?
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 13, 2014, 11:18 pm
I can only guess, but it might be possible that the Automower gives feedback that has more than 5 Bytes and therefore I have the issue. In that case the script is not in sync anymore.

However I have a new issue with your code:
Code: [Select]
if (strcmp ((char *)buffer, "digital") == 0)

I can readSensor (humidity) only if I never call doCommand or digital, analog. After I call anything else than readSensor it returns nothing anymore until restart.

Code is attached.
Title: Re: Controlling Automower
Post by: pylon on Jun 16, 2014, 11:18 am
Quote
I can only guess, but it might be possible that the Automower gives feedback that has more than 5 Bytes and therefore I have the issue. In that case the script is not in sync anymore.


That's no reason to reset the Arduino. If you're unsure clear the serial buffer from time to time.

Quote
However I have a new issue with your code:


Why do you think this has anything to do with "my" code?
Your code formatting is still horrible. Please take the time to use the AutoFormatter in the IDE at least.

Although it should make a significant difference, change the code

Code: [Select]
#define BUFFERSIZE 40
uint8_t buffer[BUFFERSIZE];
uint8_t i = 0;
while (i < BUFFERSIZE) {
  if (client.available()) {
    uint8_t c = client.read();
    if (c == '/') break;
    buffer[i++] = c;
  }
}


to

Code: [Select]
#define BUFFERSIZE 40
uint8_t buffer[BUFFERSIZE];
uint8_t i = 0;
while (i < BUFFERSIZE) {
  if (client.available()) {
    uint8_t c = client.read();
    if (c == '/') break;
    buffer[i++] = c;
  }
}
if (i < BUFFERSIZE) buffer[i] = 0;


In digitalCommand() and analogCommand() you're still using the String class. Why?
Title: Re: Controlling Automower
Post by: Dawiinci on Jun 21, 2014, 03:45 pm
Thanks it works for now. I will report back if it happens again.

Well I have another project, maybe you can give me a hint as well:
http://forum.arduino.cc/index.php?topic=248344
(http://forum.arduino.cc/index.php?topic=248344)
Title: Re: Controlling Automower
Post by: Samino on Jul 21, 2015, 02:02 pm
Hello Dawiinci,

Great project you did! I own the same automower and was looking for exactly this. How is it working for you now?
Do you have this project documented somewhere, or would you like to post the code and instructions?
That would be awesome  :)

Thanks
Sam
Title: Re: Controlling Automower
Post by: sledgehammer on Jul 29, 2015, 08:44 pm
hi dawincii

i am also interested in the whole project description

off course with a please and thank you

mario
Title: Re: Controlling Automower
Post by: pagix on Apr 28, 2016, 12:47 am
Hi dawincii,

this seems to be quite interesting, because iown a 220 :)
So I am also interested in the whole project.

Greetings

mike
Title: Re: Controlling Automower
Post by: Samino on Jun 12, 2016, 08:20 pm
Hello,

also intrested!

kr
Sam