Motorshield and electromagnet ?

Hi ,
i have a rc-car with a magnetic steering (+volts right, -volts left) which i'm controling it with a L298P Motorshield.
The only Problem is that the steering kinda vibrates an won't really move.
So my question is, how can i make the motor shield working with this electromagnet ?
Or could PLL-mode on this shield (for three-phase-motors) control it ?
Before i do anything maybe dangerous for the circuits, i want to ask someone with more experience :slight_smile:

What is the code you're using to control the motorshield? You don't want to PWM the motor driver for an electromagnet steering mechanism. Either drive it full on one direction, full on the other direction, or full off. If you PWM the signal, that will cause the electromagnet to vibrate.

Thats the code:

#include <SPI.h>
#include <Ethernet.h>
#include <Udp.h>


byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte ip[] = { 10, 56, 35, 178 };
byte gateway[] = { 10, 56, 35, 1 };
byte subnet[] = { 255, 255, 255, 0 };

#define MAX_SIZE 32 // maximum packet size
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet
byte remoteIp[4]; // holds recvieved packet's originating IP
unsigned int remotePort; // holds received packet's originating port

const int ledPin = 13;

int E1 = 5;
int M1 = 4;
int E2 = 6;
int M2 = 7;


void setup() {
  Ethernet.begin(mac, ip , gateway, subnet);
  Udp.begin(9100);
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(M1,OUTPUT);
  pinMode(M2,OUTPUT);
}

void loop() {
  int packetSize=Udp.available();  // holds received packet size
  int DriveSpeed = 0;
  boolean SteuerFehler;
  if(packetSize)
    {
    digitalWrite(ledPin,HIGH);
    int packetSize = packetSize-8;   // minus 8-Bit Header
    Udp.readPacket(packetBuffer,UDP_TX_PACKET_MAX_SIZE, remoteIp, remotePort);
    Serial.println(packetBuffer);
    }
  if(packetSize==0)
    {
    digitalWrite(ledPin,LOW);
    analogWrite(E1,0);
    analogWrite(E2,0);
    }

    
for (int i=1;i!=8;i++)    //Searches for illegal characters inside the control-string
  {
  SteuerFehler=false;
  if(packetBuffer[i]!='-' |packetBuffer[i]!='x' |packetBuffer[i]!='0' |packetBuffer[i]!='1' |packetBuffer[i]!='2' |packetBuffer[i]!='3' |packetBuffer[i]!='4' |packetBuffer[i]!='5' |packetBuffer[i]!='6' |packetBuffer[i]!='7' |packetBuffer[i]!='8' |packetBuffer[i]!='9')
    {SteuerFehler=true;}
  }
  
/*  
  
if (SteuerFehler)
  {
  Serial.println("--------Fehler--------");
  packetBuffer[0]='-';    //Reset the control-string to all off
  packetBuffer[1]='-';
  packetBuffer[2]='-';
  packetBuffer[3]='-';
  packetBuffer[4]='-';
  packetBuffer[5]='-';
  packetBuffer[6]='-';
  packetBuffer[7]='-';
    
  SteuerFehler=false;
  }
*/


//DriveSpeed
if(packetBuffer[4]!='-')
  {
    switch(packetBuffer[4]){
    case '0': DriveSpeed=30;break; 
    case '1': DriveSpeed=55;break;
    case '2': DriveSpeed=80;break;
    case '3': DriveSpeed=105;break;
    case '4': DriveSpeed=130;break;
    case '5': DriveSpeed=155;break;
    case '6': DriveSpeed=180;break;
    case '7': DriveSpeed=205;break;
    case '8': DriveSpeed=230;break;
    case '9': DriveSpeed=255;break;
    }
  } 

  
if(packetBuffer[0]=='-' & packetBuffer[1]=='-') //Stop
    {analogWrite(E1,0);}
if(packetBuffer[0]=='x')  
    {digitalWrite(M1,HIGH);analogWrite(E1,DriveSpeed);} //Reverse 
if(packetBuffer[1]=='x')                       //
    {digitalWrite(M1,LOW);analogWrite(E1,DriveSpeed);}  //Forward     

//Steering
if(packetBuffer[2]=='-' & packetBuffer[3]=='-') //Straight ahead
    {analogWrite(E2,0);}
if(packetBuffer[2]=='x')                        //Left
    {digitalWrite(M2,LOW);analogWrite(E2,255);}  
if(packetBuffer[3]=='x')                        //Right                 
    {digitalWrite(M2,HIGH);analogWrite(E2,255);}       
    

}

Steering-part is at the last lines.

I send a control-string of 8 characters, [2] is left and [3] is right, i'm always using the max. 255 for steering in one direction and LOW/HIGH. If [2] or [3] is not 'x', i set it to 0 volt.

It currently uses PWM and i'm not sure what the PLL-mode is...
When i listen to the sound that it makes, i get the feeling that the controller is giving out a stuttering (--) voltage, like on->off->on... in very fast.
Maybe the magnet could work better without that fast on-off...

Edit:
I have set the Motor2 to PLL, but i don't rellay know a thing about it.
Heres what i have figured out so far:
M2 LOW -> Does nothing on any E2-Value ?
M2 HIGH -> enables Speed Control (in only one direction ?)

With M2=HIGH and E2=0, i can turn left just fine. But what about Right ?

E1 and M1 are the FWD/Backward setting pins, Reverse is HIGH, forward is LOW.
E2 and M2 are the PWM pins, you should be able to use these as digitalWrite pins and not use pwm at all. This will send Full Left with lets say E2 at HIGH and E1 at LOW. Center is E2 = LOW. Full right would be E1 at HIGH E2 at HIGH

Back to the PWM-mode, it dosent work perfect, but at least i have left and right...

But there was something else i've noticed, the controller seems to get the signal, but then its sending out a low power (~40%) which then switches to the set power value after ~0,5 seconds delay.
shouldn't it give out the full power instantly ?

Is it possible for you to try using digitalWrite(,HIGH) instead of outputting PWM? I would like to see of this changes anything as far as output power goes.

HIGH is the same as 255.

Your control for receiving input and controlling the car is a bit... wonky (no offense intended) and overcomplicated. I can't see anything that will obviously cause the problems you are seeing, but a more simplified control scheme will not only make it easier to debug, but make it less likely that there will be a problem to debug from the start.

To that end, don't even bother checking for invalid characters. Since you only perform actions based on valid characters, there's little benefit being gained by doing so.

Only set IO points when you receive a command packet. There's no benefit to repeatedly setting IO points to the same values over and over and over. Again, there shouldn't technically be anything wrong with doing so, but it can make diagnosing and debugging problems more of a headache than it already is.

So, as sort of some pseudo-code to go by:

if(packetavailable){
  receive packet
  perform drive control
  perform steering control
}

You can also easily reduce your drive control down to a single byte and your steering control down to a single byte.

Steering control byte would just be a three state control.
val1 = straight ahead
val2 = left
val3 = right

Drive control would only be slightly more complicated. Using a signed char variable, you have a range of -127 to 127. if the val is less than 0, set you direction to reverse, otherwise set it to forward. Take the absolute value of the variable, multiply it by 2 (then add 1 if you absolutely want the max speed possible, but the reality is the difference between 254 and 255 is likely negligible), and that's your speed.

Thanks a lot jraskell, i deleted the in fact useless check-part and moved the controls into the the "if(packetsize)".

The stuttering is also solved now, it was propably caused by:

  if(packetSize==0)
    {
    digitalWrite(ledPin,LOW);
    analogWrite(E1,0);             
    analogWrite(E2,0);           
    }

this always activates when there are no packets, which is always the case right after a packet.
So i removed the two "analogWrite()" and it was gone :smiley:

About making the controls bitwise, i had that in mind before, but i couldn't get the RAW-Data from UDP...

Good to hear. I never even noticed those lines from your original code, but that is clearly what was causing your problems.

As another side note, you may want to look at the difference between & and && as well as | and ||. For what you're doing in your comparisons, the bitwise & and | operators are still accomplishing your goal, but you really should be using the boolean && and || operators in comparisons.