
Simple remote control from a computer by a robot
Preface or why pervert?
Hello, Habrahabr! I sat on the evening of June 11, watched a movie. Unexpectedly for myself, I discovered that an unknown woman had written to me with an offer to make a robot for their new quest. The bottom line is that you need to solve puzzles, explore caches, correctly use hints, use accessible things and finally get keys and open doors ... I was required to make a robot controlled from a computer using a separate program. The furniture had doubts about some problems, for example: will I be in time and how to make wireless data transfer (before that I was engaged in wireless data transfer only on the NXT)? After weighing the pros and cons, I agreed. After that, I began to think about data transfer. Since it was required to make the robot quickly, there was no time to remember and retrain, for example, Delphi, so the idea came up to make a module that will deal with sending commands. From the computer you just need to send data to the COM port. This method is strange, but the fastest. I want to describe him here. I will also attach 3 programs that will help to make a radio-controlled machine.
The assembly of the transmitter and its program.
I made a computer module from FTDI Basic Breakout 5 / 3.3V from DFrobot, a fairly common ATMEGA 328P-PU microcontroller with an Arduino bootloader and a radio module based on the nRF24L01 chip. In fact, it's just an Arduino Uno with a radio module. It is what it is. The radio module has a feature that I did not immediately notice: the input voltage should be in the range from 3 to 3.6 volts (although supplying it with 5 volts will not kill it, but will not work), the upper limit of the logical unit is 5V. This means that to connect the radio module to the mega, you do not need a level converter between 3.3V and 5V, but you need to install a 3.3V stabilizer. FTDI has a built-in stabilizer, and from it I fed the radio module.
This is how the module itself looks (inside and in the assembly):

The program consists of initialization, start message and processing of commands from the control program. So it was in my case. Basic Mirf Library Commands:
#include
#include
#include
#include
#include
These libraries are needed for the operation of the radio module
Mirf.csnPin = 4 - sets the pin number responsible for the “permission to communicate” radio module and MK
Mirf.cePin = 6 - sets the number of the pin responsible for the radio module operation mode (receiver / transmitter)
Mirf.spi = & MirfHardwareSpi - sets the SPI line
Mirf.init () - initializes the radio module
Mirf.payload = 1 - the size in bytes of one message (default 16, maximum 32)
Mirf.channel = 19 - sets the channel (0 - 127, default 0)
Mirf.config () - sets the transmission parameters
Mirf.setTADDR ((byte *) "serv1") - puts the radio module in the transmitter mode
Mirf.setRADDR ((byte *) "serv1") - translates p radio module in receiver mode
Mirf.send (data) - sends an array of type byte
Mirf.dataReady () - reports the end of processing received data
Mirf.getData (data) - write the received data to the data array
Mirf.setTADDR ((byte *) "serv1") - puts the radio module in transmitter mode
Mirf.setRADDR ((byte * ) "Serv1") - puts the radio module in receiver mode
Mirf.send (data) - sends an array of type byte
Mirf.dataReady () - reports the end of processing received data
Mirf.getData (data) - writes the received data to the data array I
enclose the program code the transmitter.
Transmitter program
#include
#include
#include
#include
#include
char active;
byte data [1];
void setup ()
{
Serial.begin (19200);
Mirf.csnPin = 4;
Mirf.cePin = 6;
Mirf.spi = & MirfHardwareSpi;
Mirf.init ();
Mirf.payload = 1;
Mirf.channel = 19;
Mirf.config ();
Mirf.setTADDR ((byte *) "serv1");
// alarm message about the beginning of work
data [0] = 7;
Mirf.send (data);
delay (200);
}
void loop ()
{
if (Serial.available ()) // If the data is ready to be read
{
active = Serial.read (); // Write data to a variable
}
if (active == '2')
{
data [0] = 2;
}
if (active == '3')
{
data [0] = 3;
}
if (active == '4')
{
data [0] = 4;
}
if (active == '5')
{
data [0] = 5;
}
if (active == '6')
{
data [0] = 6;
}
Mirf.send (data); // Send data
while (Mirf.isSending ()); // Wait for the data to be sent
}
#include
#include
#include
#include
char active;
byte data [1];
void setup ()
{
Serial.begin (19200);
Mirf.csnPin = 4;
Mirf.cePin = 6;
Mirf.spi = & MirfHardwareSpi;
Mirf.init ();
Mirf.payload = 1;
Mirf.channel = 19;
Mirf.config ();
Mirf.setTADDR ((byte *) "serv1");
// alarm message about the beginning of work
data [0] = 7;
Mirf.send (data);
delay (200);
}
void loop ()
{
if (Serial.available ()) // If the data is ready to be read
{
active = Serial.read (); // Write data to a variable
}
if (active == '2')
{
data [0] = 2;
}
if (active == '3')
{
data [0] = 3;
}
if (active == '4')
{
data [0] = 4;
}
if (active == '5')
{
data [0] = 5;
}
if (active == '6')
{
data [0] = 6;
}
Mirf.send (data); // Send data
while (Mirf.isSending ()); // Wait for the data to be sent
}
Management program.
There is one interesting thing - Processing. The syntax is the same as in Arduino, but instead of void loop (), void draw () is located there. But it became even more interesting in my situation with the processing Serial library, which allows you to work with a serial port. After reading the lessons on Spurkfun’s website, I played around with a blinking LED on the mouse connected to the computer arduinka. After that I wrote a robot control program from the keyboard. I enclose the control code using the arrows. In it, in principle, there is nothing unusual.
Typewriter control program
import processing.serial. *;
import cc.arduino. *;
Serial myPort;
PFont f = createFont ("LetterGothicStd-32.vlw", 24);
void setup ()
{
size (360, 160);
stroke (255);
background (0);
textFont (f);
noCursor ();
String portName = "XXXX"; // Here you need to write the name of your port
myPort = new Serial (this, portName, 19200);
}
void draw () {
if (keyPressed == false)
{
clear ();
myPort.write ('6');
println ("6");
}
}
void keyPressed ()
{
// 10 - enter
// 32 - probel
// 37/38/39/40 - keys
clear ();
fill (255);
textAlign (CENTER);
// text (keyCode, 180, 80);
switch (keyCode)
{
case 37:
text ("Edem vlevo", 180, 80);
myPort.write ('1');
break;
case 38:
text ("Edem pryamo", 180, 80);
myPort.write ('2');
break;
case 39:
text ("Edem vpravo", 180, 80);
myPort.write ('3');
break;
case 40:
text ("Edem nazad", 180, 80);
myPort.write ('4');
break;
default:
text ("Takoy kommandi net", 180, 80);
myPort.write ('6');
break;
}
}
import cc.arduino. *;
Serial myPort;
PFont f = createFont ("LetterGothicStd-32.vlw", 24);
void setup ()
{
size (360, 160);
stroke (255);
background (0);
textFont (f);
noCursor ();
String portName = "XXXX"; // Here you need to write the name of your port
myPort = new Serial (this, portName, 19200);
}
void draw () {
if (keyPressed == false)
{
clear ();
myPort.write ('6');
println ("6");
}
}
void keyPressed ()
{
// 10 - enter
// 32 - probel
// 37/38/39/40 - keys
clear ();
fill (255);
textAlign (CENTER);
// text (keyCode, 180, 80);
switch (keyCode)
{
case 37:
text ("Edem vlevo", 180, 80);
myPort.write ('1');
break;
case 38:
text ("Edem pryamo", 180, 80);
myPort.write ('2');
break;
case 39:
text ("Edem vpravo", 180, 80);
myPort.write ('3');
break;
case 40:
text ("Edem nazad", 180, 80);
myPort.write ('4');
break;
default:
text ("Takoy kommandi net", 180, 80);
myPort.write ('6');
break;
}
}
Receiver program.
The initialization of this program differs from the initialization of the transmitter program in just one line. The key command in the infinite loop is Mirf.getData (data). Further, the received command is compared with numbers that correspond to any actions of the robot. Well, then the robot acts exactly on commands. I enclose the program code of the
Typewriter programs
#include
#include
#include
#include
#include
void setup ()
{
Serial.begin (9600);
pinMode (13, OUTPUT); // LED
Mirf.csnPin = 10;
Mirf.cePin = 9;
Mirf.spi = & MirfHardwareSpi;
Mirf.init ();
Mirf.payload = 1;
Mirf.channel = 19;
Mirf.config ();
Mirf.setRADDR ((byte *) "serv1");
}
void loop ()
{
byte data [1];
if (! Mirf.isSending () && Mirf.dataReady ())
{
Mirf.getData (data);
Serial.println (data [0]);
}
switch (data [0])
{
case 1:
motors (-100, 100); // turn left
break;
case 2:
motors (100, 100); // drive straight
break;
case 3:
motors (100, -100); // turn right
break;
case 4:
motors (-100, -100); // go back
break;
default:
motors (0, 0); // stand
break;
}
delay (50);
}
#include
#include
#include
#include
void setup ()
{
Serial.begin (9600);
pinMode (13, OUTPUT); // LED
Mirf.csnPin = 10;
Mirf.cePin = 9;
Mirf.spi = & MirfHardwareSpi;
Mirf.init ();
Mirf.payload = 1;
Mirf.channel = 19;
Mirf.config ();
Mirf.setRADDR ((byte *) "serv1");
}
void loop ()
{
byte data [1];
if (! Mirf.isSending () && Mirf.dataReady ())
{
Mirf.getData (data);
Serial.println (data [0]);
}
switch (data [0])
{
case 1:
motors (-100, 100); // turn left
break;
case 2:
motors (100, 100); // drive straight
break;
case 3:
motors (100, -100); // turn right
break;
case 4:
motors (-100, -100); // go back
break;
default:
motors (0, 0); // stand
break;
}
delay (50);
}
Conclusion
What came of it all:
I made this robot for Claustrophobia . They carry out quests in reality in different cities, and just for one of these quests the organizers needed a radio-controlled robot sapper. I like it. This, of course, is flawed, because against the background of control using the means of communication built into the laptop, but its own, made very quickly and without any problems. I hope this article helps to do something similar, and maybe even more difficult. Then someone wants what.