PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Arduino mit Perl steuern



Scritped
27.09.2014, 17:04
Hallo zusammen,

seit graumer Zeit versuche ich mein Arduino über Perl anzusteuern, doch leider ohne Erfolg.
Mein aktueller Code sieht wie folgt aus:

use strict;
use warnings;
use Win32::SerialPort;

my $ob = Win32::SerialPort->new ('COM3') || die;
$ob->debug(0);

my $baud = $ob->baudrate;
my $data = $ob->databits;
my $parity = $ob->parity;
my $stop = $ob->stopbits;
my $hshake = $ob->handshake;

print "Baudrate: $baud\n"; # just debugging
print "Paritaet: $parity\n";
print "Datenbits: $data\n";
print "Stoppbits: $stop\n";
print "Flusssteuerung: $hshake\n";

$ob->baudrate(9600) || die "fail setting baud";
$ob->parity($parity) || die "fail setting parity";
$ob->databits($data) || die "fail setting databits";
$ob->stopbits($stop) || die "fail setting stopbits";
$ob->handshake($hshake) || die "fail setting handshake";
$ob->write_settings || die "no settings";
$ob->save("COM_3.cfg");

print "Writting ... "; <STDIN>;
$ob->write("1");

my $result = $ob->input;
print "result = $result\n";


#define ledPin 11
int incomingByte;

void setup() {

Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}

void loop() {
if (Serial.available() > 0) {

incomingByte = Serial.read();

if (incomingByte == '1')
{
digitalWrite(ledPin, HIGH);
Serial.println("LED ist eingeschaltet!");
}

if (incomingByte == '0')
{
digitalWrite(ledPin, LOW);
Serial.println("LED ist ausgeschaltet!");
}
}
}
]

Außer der Herstellung der Kommunikation, klappt nichts. Mit dem Code habe ich vor, mithilfe von Perl die PINs zu definieren und zu setzen. Natürlich will ich auch die Ausgabe in einen String packen.


Ich hoffe jemand kann mir helfen oder mir zuverlässige Quellen nennen - bis jetzt habe ich nichts anständiges/vollständiges finden können. :(


Equipment:
Arduino UNO,
Win7 - 64x,
Stawberry Perl 5.16 - Win32::SerialPort.

Bitte um Rückmeldung!

Gruß.

Sisor
28.09.2014, 00:04
Außer der Herstellung der Kommunikation, klappt nichts.
Welche Kommunikation läuft?
Brauchst du Hilfe, um obigen Code zum Laufen zu bekommen, oder funktioniert der Code und du kommst jetzt nicht weiter?

Scritped
28.09.2014, 08:02
Welche Kommunikation läuft?
Brauchst du Hilfe, um obigen Code zum Laufen zu bekommen, oder funktioniert der Code und du kommst jetzt nicht weiter?

Nun, ich kann die Baudrate etc. auslesen und auch erfolgreich setzen. Nur beim senden und empfangen von Daten habe ich Probleme. Z.B. mit $Var->write("1"); sende ich eine 1 an das Arduino was eigentlich dazu führen müsste, das mir der jeweilige PIN gesetzt wird und meine LED leuchtet. Außerdem will ich mit $Var->input(); das lesen können was im SerialMonitor ausgegeben wird.

Gruß.

Sisor
28.09.2014, 11:13
Einstellung des Ports sollten sein:
-kein Handshake
-kein Parity
-1 Stopbit
-8 Databits

(Klappt bei mir in meinem C#-Programm)

Der Port kann imho nicht gleichzeitig vom SerialMonitor und deinem Perlprogramm benutzt werden.

Scritped
28.09.2014, 13:35
Einstellung des Ports sollten sein:
-kein Handshake
-kein Parity
-1 Stopbit
-8 Databits

(Klappt bei mir in meinem C#-Programm)

Der Port kann imho nicht gleichzeitig vom SerialMonitor und deinem Perlprogramm benutzt werden.

Genau die Einstellungen am Port habe ich.
Das mit dem gleichzeitigem Nutzen eines Ports ist soweit auch klar.

Woran kann es den noch liegen, das ich nichts "senden" kann an's Arduino?

Sisor
28.09.2014, 16:40
Aus deinem Perl-Quelltext:
$ob->write_settings
Ist das nicht eine Methode? Dann muß es heißen:
$ob->write_settings()

Scritped
28.09.2014, 18:04
Aus deinem Perl-Quelltext:
$ob->write_settings
Ist das nicht eine Methode? Dann muß es heißen:
$ob->write_settings()

Hm, bis jetzt hat es keine Probleme gemacht dabei, hast aber Recht. ;) Hilft mir aber bei meinem eigentlichem Problem nicht weiter ... :(

Wärst Du so nett und könntest Deinen C#-Programm mal uppen?

Gruß.

Sisor
28.09.2014, 20:30
Ok. Hier mein C#-Arduino-Kommunikations-Programm.
-Es ist zugeschitten auf das oben gepostete Arduino-Programm.
-Es ist ein einfaches Konsolenprogramm, das sich den Arduino-Port selbst sucht.
-Im Projektmappenexplorer von Visual-Studio:

Rechtsklick auf das Projekt im Projektexplorer
Hinzufügen -> Verweis
Haken bei System.Management hinzufügen (Framework)




--- Hauptprogramm ---

using System;
using System.IO.Ports;
using System.Linq;
using System.Threading;

namespace ConnectToArduino
{
class Program
{
static void Main(string[] args)
{
#region --- Start ---
ConnectionManager manager = new ConnectionManager();
SerialPort arduinoPort;
if (manager.SerialPorts.Count > 0)
{
arduinoPort = manager.SerialPorts.ElementAt(0).Value;
Console.WriteLine("Arduino found: {0}\n", manager.SerialPorts.ElementAt(0).Key);
}
else
{
Console.WriteLine("No Arduino found!");
Console.WriteLine("<Press Key to exit program>");
Console.ReadKey();
return;
}
try
{
arduinoPort.Open();
}
catch (Exception)
{
Console.WriteLine("Port already open!");
Console.WriteLine("<Press Key to exit program>");
Console.ReadKey();
return;
}
#endregion


#region --- Send and Receive ---
arduinoPort.Write("1");
Thread.Sleep(100);
Console.WriteLine("Response from Arduino after sending \"1\": {0}", arduinoPort.ReadLine());
Thread.Sleep(1000);

arduinoPort.Write("0");
Thread.Sleep(100);
Console.WriteLine("Response from Arduino after sending \"0\": {0}", arduinoPort.ReadLine());
Console.WriteLine("<Press Key to exit program>");
Console.ReadKey();
#endregion


#region --- End Program ---
try { arduinoPort.Close(); }
catch (Exception){ return; }
#endregion
}
}
}


--- ConnectionManager ---

using System.Collections.Generic;
using System.Diagnostics;
using System.IO.Ports;
using System.Linq;
using System.Management;

namespace ConnectToArduino
{
public sealed class ConnectionManager
{
public Dictionary<string, SerialPort> SerialPorts { get; private set; }

public ConnectionManager()
{
FindArduinoDevices();
}

private void FindArduinoDevices()
{
var dict = new Dictionary<string, SerialPort>();
try
{
foreach (ManagementObject device in
new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_SerialPort").Get())
{
if (!device["PNPDeviceID"].ToString().Contains("VID_2341")) continue;
var port = new SerialPort();
var config = device.GetRelated("Win32_SerialPortConfiguration")
.Cast<ManagementObject>().ToList().FirstOrDefault();
port.PortName = device["DeviceID"].ToString();
port.BaudRate = (config != null)
? int.Parse(config["BaudRate"].ToString())
: int.Parse(device["MaxBaudRate"].ToString());
dict.Add(device["Description"].ToString(), port);
}
SerialPorts = dict;
}
catch (ManagementException mex)
{
Debug.WriteLine(@"An error occurred while querying for WMI data: " + mex.Message);
}
}
}
}

California_EV
12.10.2014, 19:28
Hallo,

ist der Thread hier beendet? Ich kenn mich in den Foren noch nicht so gut aus. Ich hätte da vielleicht eine Antwort,
auf jeden Fall aber ein Problem mit dem Arduino und Perl.

Gruß Jürgen

Scritped
12.10.2014, 20:20
Hallo,

der Thread und auch das Problem besteht noch. :)
Leider habe ich auch bis jetzt keine Zeit dafür gehabt.

Gruß.

California_EV
12.10.2014, 22:24
Hallo,
ich hab einen Antennenrotor gebaut den ich via Arduino und Perl steuere.
Ich greife auf den Steuerrechner(Dachboden) via ssh von meinem Shack zu.
Das ganze funktioniert sehr gut bis auf ein kleines Problem das ich am Ende beschreibe.


Als erstes mein Lösungsanzatz, nicht relevater Code lasse ich weg und
ich habe versucht die einzelenen Aktionen in Funktionen zu packen.

Arduino

RS232 init:


void setup ()
{
Serial.begin (9600);
}


RS232 einlesen:
Mit der Methode wir ASCII eingelesen. In meinem Fall
3 Ziffern die dann in Zahlen gewandelt werden um dann eine
3-stellige Zahl zu werden. Beispiel: wenn 1 gesendet wird
kommt eine ASCII 49 die durch -48 zur 1 wird. Siehe ASCII-Tabelle


/* Sollwinkel via serieller Schnittstelle Empfangen
Sollwinkel muss 3-Stellig + LF uebertragen werden
*/
void Empfangen(){
int count = 0; // eingehende Byte zaehlen
beschleunigung=true; // => 1x bei neuem Winkel Motor in der Regelschleife hochfahren
schleichgang=false;
boolean ok = true;
while(ok){
if (Serial.available () > 0){
incomingByte = Serial.read ();
data_in[count] = incomingByte;
count++;
if (incomingByte == 10){ // dez 10 = Zeilenende
ok=false;
}
}
}
}


RS232 ausgeben:


/*Info an serielle Schnittstelle senden*/
void RS232OUT(){
Serial.println("Winkel liegt an. Done");
delay(10);
}


Perl via Linux
Ich denke man kann den Code leicht in die Windows-Welt umsetzen.

RS232 init:


use Device::SerialPort;
# init globale Variablen
my $port = Device::SerialPort->new("/dev/ttyACM0");
my $PeilungSoll="";
my $VonArduino="";


an Arudino senden:


sub senden{
my $Var=shift @_;
$port->write($Var); # via RS232 senden
return(1);
}


von Arduino empfangen:


sub empfangen{
my $Input="";
my $OK=0;
until($OK){
sleep(1);
$Input = $port->lookfor(); # von RS232 lesen
if ($Input) {
$OK=1;
$port->lookclear; # Buffer loeschen?
}
}
return($Input);
}


Nun zu meinem Problem. Auf der Werkbank "hundert" mal geteste.
Jetzt hab ich die Steuerung auf dem Dachboden und bediene den Rotor
von einem anderen Raum. Die Rechner sind via Netzkabel verbunden.
Es kommt zu sporadischem hägenbleiben bei meinem Perlprogramm.
Nach einem Durchlauf soll der Arduino "ferig melden". Perl wartet
in einer Schleife auf diese Meldung. Ich denke der Arduino liefert nicht.
Ich sehe meinen Rotor ist in Position. Der Motor ist aus. Nun müsste via
RS232 die Meldung vom Arduino kommen und mein Perlprogramm wieder
in die Eingabe springen, tut es aber nicht immer.

Viel Text, aber man muss ja die Sachlage einigermaßen genau schlidern.
Hat jemand eine Rat?

Gruß