Controlling Robot via Simulated Neurons (pt.1)

Hello!

Note that the title says simulated and not stimulated. The current goal is to run the robot in a closed-loop with a neuronal cell culture, but a step in getting there is running the robot off of some simulated neurons. Here, I’ll explain what I’ve done since last time:

In the last two posts, I discussed how to send packets to Arduino via XBee, and how I controlled my robot via MATLAB. The next step, then, was controlling the robot via packets I send through MATLAB :). I’ll start with the necessary background:

Simulating a Neural Network

In brief, there are plenty of freely-available, advanced neural networks to use. Examples: Izhikevich’s, and the Fitzhugh-Nagumo, which is a one-dimensional version of the traditional Hodgkin-Huxley model. Needing only a few neurons in the simulated network, however, these models are too complicated for my purposes.

I discussed this briefly in the previous post, but I have chosen to use this customizable neural network. I modified a bit of code to create a network of 4 neurons, of which I will use 2–one for each wheel of the robot.

W = log(abs(randn(4)));
[spk NetParams V] = SimLIFNet(W,'simTime',35,'tstep',1e-2,...
'offsetCurrents',1.1*ones(length(W),1));
v = round(V, 3);

I am taking advantage of V (from which I derive v), which is a matrix of about  4 x 3500 cells that represent the neurons’ spiking.

The MATLAB Code

Here’s the final version, but I’ll also take you through why I did what I did below.

%This is the setup that does not need to be repeated

s = serial('COM13', 'BaudRate', 9600, 'Terminator', 'CR', 'StopBit', 1, 'Parity', 'None');
fclose(s);
fopen(s);

%Now I'm just going to do
%some setup for the coming loop
%remember that 'v' has already been created
%(see above)

for a = 1:700
num = a*5;
left(a)=v(3,num);
end
for a = 1:700
num = a*5;
right(a)=v(1,num);
end
newright = right*100;
newleft = left*100;
startright = '{';
endright = '}';
startleft = '[';
endleft = ']';

%Here's the good stuff lol:
for a = 1:700
numr = int2str(newright(a));
numl = int2str(newleft(a));
pacl = strcat(startleft, '.', numl, endleft);
pacr = strcat(startright, '.', numr, endright);
fprintf(s, pacr);
fprintf(s, pacl);

%pause(1)
%^ that's commented out right now because
% leaving it in would make this loop take
% muuuuch longer :)

end

%The main loop has now finished, but I want the motors to stop running
fprintf(s, '{.00}')
fprintf(s, '[.00]')

%Always remember to do this before you finish!
fclose(s);

Code: Why I Did What I Did

So below is a screenshot of some of my initial code working. Here, I was very simply sending a decimal number stylized as a packet through MATLAB to the Arduino. In case it isn’t clear, the line I sent says

fprintf(s, '{.124}');

and it shows up nicely on the Arduino Serial Monitor! Hooray! 😀

— — —

The next thing I did was modify the Arduino Code so that it could receive both ‘left’ and ‘right’ speeds and process them independently. Below is a picture of it working… what’s weird is that this correctly identified and printed left vs. right motor speeds, but the ‘original’ string that it displayed always had double values. For example, if I had sent ‘.123’, it would display ‘.112233’. I couldn’t figure out how to fix that, but it wasn’t causing much of an issue, so I thought I’d document it in case it caused issues later on. 🙂

— — —

So inserted below is a quick picture of how I was testing different functions. You’ll notice that I write the variable ‘ran’ as a whole number, convert it to a string, struncate it with the ‘start’ and ‘end’ characters, and include a strange ‘.’ in there as well. That ‘.’ is me converting the whole number into a decimal number.

Why did I go through this long and convoluted process? See below:

Going through it line by line:

  • If I try to struncate the number ‘ran’ with two strings (the start and end characters), I get something weird that looks like {A}. This has to do with ASCII values.
  • This is not how you instantiate ‘ran’ as a char (?)
  • It turns out the string function (as in “convert to string”) that I found online in the official MATLAB  reference is now obsolete
  • char(ran) is not the same thing as string(ran); it doesn’t have the same functionality, so was not useful for my purposes
  • I found a function that does work! int2str is what I’ll be using now.
  • …except int2str does not support decimal numbers. (I couldn’t figure out MATLAB’s version of doubles, so this is why I’m converting to a decimal number using ‘.’ above).

The Arduino Code

I took the code from the previous post, and added the necessary modifications. Here’s a quick rundown of what I did:

  • Add a new segment to interpret the incoming packets so they can be differentiated between left and right motors. (‘[]’ vs ‘{}’).
  • Add Motor functions in the beginning to regain the ability to control them
  • Add a new function at the very end that does about the same thing as the previous ‘void function()’, but this time returns a value :).

Here it is:

//all the necessary Motor stuff begins
class Motor{
 private:
 int pin_enable; //this is the thing that you set the speed with
 int pin_forward; //basically each motor has two of these pins, 
 int pin_backward; //and you use them to reverse polarity and switch direction
 
 public:
 Motor(int enable, int one, int two){
 pin_enable = enable;
 pin_forward = one;
 pin_backward = two;
 //in the old code they essentially combined these last two steps with something fancy
 //oh well, this is easier to understand lol
 }
 void motorSpeed(int Speed){
 if(Speed > 0 || Speed == 0){ //here, I'm asking which way to set the polarity, with the idea being that I can input pos. or neg. speeds into the function
 digitalWrite(pin_forward, HIGH);
 digitalWrite(pin_backward, LOW);
 analogWrite(pin_enable, Speed);
 }
 else{
 digitalWrite(pin_forward, LOW);
 digitalWrite(pin_backward, HIGH);
 analogWrite(pin_enable, -Speed);
 }
 }
};

//Reverse Polarity protector is plugged into Pin 12 on the MEGA shield
Motor right_motor(5, 42, 43);
Motor left_motor(6, 44, 45);
char SIDE;
int right_speed;
int left_speed;

void setSpeeds(int bothSpeed){
 right_motor.motorSpeed(bothSpeed);
 left_motor.motorSpeed(bothSpeed);
 }

void turn(int bothSpeed)
{
 right_motor.motorSpeed(bothSpeed);
 left_motor.motorSpeed(-bothSpeed);
}

//all the necessary Motor stuff ends

//note: I have included all the Motor functions here,
//but I only plan on using 'up to' motorSpeed, because 
//the two wheels will be operating independently
//of one another
 
void setup() {
 // initialize serial ports
 Serial.begin(9600); // USB serial port 0
 Serial.println("Starting up...");
 Serial3.begin(9600); // serial port 3
}
byte rx_byte = 0; // stores received byte
String str;
String stri;

void loop() {
 if (Serial.available()) {
 rx_byte = Serial.read();
 Serial3.write(rx_byte);
 }
 if (Serial3.available()) {
 rx_byte = Serial3.read();

//this is the the code for the RIGHT wheel
 if(rx_byte == '{')
 {
 Serial.println("--RIGHT--");
 str = "";
 }
 else if(rx_byte == '}')
 {
 Serial.println();
 Serial.println("final string: " + str);
 // function(str);
 int rightSpeed = detectSpeed(str);
 Serial.println(rightSpeed);
 right_motor.motorSpeed(rightSpeed);
 Serial.println("--END RIGHT--");
 }
 else{
 Serial.write(rx_byte);
 char c = rx_byte;
 str = str + c;
 }
 
//I'm going to try and use a different character to differentiate the left vs. right
//let's see if it works...

//this is the code for the LEFT wheel
if(rx_byte == '[')
 {
 Serial.println("--LEFT--");
 stri = "";
 }
 else if(rx_byte == ']')
 {
 Serial.println();
 Serial.println("final string: " + stri);
 //function(stri);
 int leftSpeed = detectSpeed(stri);
 Serial.println(leftSpeed);
 left_motor.motorSpeed(leftSpeed);
 Serial.println("--END LEFT--");
 }
 else{
 Serial.write(rx_byte);
 char d = rx_byte;
 stri = stri + d;
 }
 }
 
}
void function(String str)
{
 double num = str.toFloat();
 Serial.print("String to Float: ");
 Serial.println(num);
 double other = num*250;
 Serial.print("The Wheel Speed: ");
 Serial.println(other);
}

int detectSpeed(String st)
{
 double num = st.toFloat();
 double other = num*250;
 int ans = other;
 return ans;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *