C# serial command to move Arduino servo X degrees? - c#

I have an Arduino wired up with a servo (Pin 9, 5.5v and Ground), it will run with any ol' testing on the Arduino; however, when I send a serial command to move it, well nothing happens. The rx light flashes so I know the Arduino is getting the info. I think the issue is in my byte conversion.
Code Time:
Arduino Code:
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// a maximum of eight servo objects can be created
void setup()
{
myservo.attach(9);
// attaches the servo on pin 9 to the servo object and sets the rotation to 0
myservo.write(0);
}
int pos1= 0;
int pos2= 0;
int pos3= 0;
int totalMove = 0;
void loop()
{
if (Serial.available() > 0 && totalMove > 0)
{
pos1 = Serial.read() - '0';
// pos2 = Serial.read() - '0';
// pos3 = Serial.read() - '0';
// totalMove = ((pos3) + (pos2*10) + pos1*100);
myservo.write(pos1);
}
}
You see the other pos holders because evenutally I would like to be able to send values larger than 9, however for now I just need to get it to respond :)
C# code:
public void moveServo()
{
if (!serialPort1.IsOpen)
{
Console.WriteLine("Oops");
serialPort1.Open();
return;
}
serialPort1.DtrEnable = true;
serialPort1.DataReceived +=
new System.IO.Ports.SerialDataReceivedEventHandler(
serialPort1_DataReceived);
serialPort1.Write(new byte[] {57}, 0, 1);
}
Any ideas?

Have you made sure it works using other software? That's typically the first step, even if you have to use hyperterminal. That'll shake out any cable problems and give you the correct parameters.
Also I recommend PortMon, from SysInternals. It lets you monitor serial port activity while your application runs.
Make sure you're setting all the serial port parameters; baud rate, data bits, stop bits, parity, handshake, and read and write timeout. You can also set the value to use for a NewLine character.
Also, rather than relying on the data recieved event, you might try reading it yourself.

You are sending this byte
serialPort1.Write(new byte[] {57}, 0, 1);
which basically is the character '9'. The receiver code is
pos1 = Serial.read() - '0';
which means that pos1 has the value 9 (note the missing '). This value is then written directly to the Servo instance.
myservo.write(pos1);
Summing together all parts: You can effectively send only the values 0 to 9 to the servo. But the reference page tells you that write requires the range 0 to 180. Sending only 0 to 9 to the servo might just wiggle it a little bit.

maybe it's because of your logic level.
the lpt and serial port output is 2.5v and some driver's need 5v to set and reset.
so you need an ic like max232 to convert logic level from 2.5v to 5volt.

Related

Drawing data obtained from Serial Port progresively getting slower

I am working on voltmeter application, that draws voltage waveform. Hardware sends 1000 numbers (range 0 - 1023, always whole numbers) in string format per second through serial port.
public SerialPort serialPort = new SerialPort("COM3", 57600);
serialPort.Open();
String is converted into int and then drawn with DrawLine into PictureBox.
// variable declarations, all is int, runs in its own thread
while (blToMeasure) // true after clicking on button
{
iPrevY = iY;
iY = Int16.Parse(serialPort.ReadLine());
graphicsGraph.DrawLine(penBlack, iX, iPrevY, iX + 1, iY);
// only this thread is accessing PictureBox
iX++;
if (iX > picBoxGraph.Width)
{
graphicsGraph.Clear(SystemColors.Control);
iX = 0;
}
if (iY > picBoxGraph.Height)
{
}
}
Issue is that drawing lines itself is fast as it should be only for a couple of seconds, but gets gradually slower.
I tried Int.Parse, Int32.Parse and splitting thread function multiple ways using lock (graphicsGraph) (moving conditions with Clear into another thread) or using BlockingCollection<int> (moving DrawLine into another thread, away from Parse). Nothing seems to work and app still gets slower a couple of times after like a minute of running.
There isn't issue with hardware itself, checked with another software. Is this too fast for C#?
Solution:
I got the best results using Port.ReadTimeout = 1 and Port.DiscardInBuffer(). Also using Form.DoubleBuffered = true, but it doesn't make a huge difference in this particular case.
// constructor
Port.ReadTimeout = 1;
Form.DoubleBuffered = true;
Here is the loop itself:
btn.Click() // click to start measuring
{
Port.DiscardInBuffer();
blToMeasure = true;
}
while (blToMeasure) // true after clicking on button
{
iPrevY = iY;
try {
iY = Int16.Parse(serialPort.ReadLine());
}
catch
{
// exception logic
}
graphicsGraph.DrawLine(penBlack, iX, iPrevY, iX + 1, iY);
// only this thread is accessing PictureBox
iX++;
if (iX > picBoxGraph.Width)
{
graphicsGraph.Clear(SystemColors.Control);
iX = 0;
}
if (iY > picBoxGraph.Height)
{
}
}
When the app starts to read from the port, there is always accumulated data, because my hardware is sending numbers all the time, so I get rid of the buffer. Than the drawing of lines is not executed in differing spikes and the speed is constant. Analyzing the issue with Watch, I found out, that it occasionaly takes much longer to read this data and because of 1000 reads per second, it slows down. So to prevent slowing down, I used Port.ReadTimeout, that skips the read, if it takes too long.
The difference is visible, drawing no longer slows down and it keeps the same pace for minutes from what I've tried. I consider this sufficient solution for my issue, thank you!

C# How to wait for serial port action to finish until doing next read action

first up I try to specify the question. I have 2 devices connected via Serial Port to my Laptop. SerialPort2 is a Sensor, the other is a Motor. I saved a specific Motorposition earlier in the programm. I now want the motor to return to this position and then read the value from the sensor.
Communication with the motor looks like this:
Send 9-byte-array which stores input information to the motor
Serial Port answers with a 9-byte-array, according to which command was send. getPosi() takes an empty array, fills it with the nessecary information and sends a command which translates to "tell me your current positon", and the answer contains this position.
I catch all answers with DataReceived in a global buffer-variable "buf" (which is overwritten after each command i send), and store the position I need later in the programm in another global "M"-varibal (seperate Save-Method). The problem is now, that if i send the command MoveToSave() I immediately get an answer, the motor still rotates and the next read() is executed (hence i dont get the value i want).
Here would be the code, if any important info to understand the code is missing, i will add later.
private void button14_Click(object sender, EventArgs e)
{
//move to save
byte[] E = new byte[9];
MoveToSave(E);
byte[] F = new byte[9];
do
{
getPosi(F); //overwrites buf with current position
}
while (M != buf)
//code below is needed to get readable value from sensor
serialPort2.WriteLine("SR,00,002\r\n");
string b = serialPort2.ReadLine();
decimal b1 = decimal.Parse(Regex.Split(b, "SR,00,002,")[1]);
decimal Diffb = Math.Abs(b1 - caliberMid);
textBox1.Text = "Mid Wall Thickness: " + Diffb;
//move to 0
byte[] D = new byte[9];
MoveTo0(D);
}
So the question would be, how to realize that the serialPort2.ReadLine() is only executed after the motor returned to its saved position. The way I have it currently does not work. It shows me the answer from getPosi(), and its the same as my stored "M" but it does not break the loop. There is no answer send by the motor that signals a stop in rotation. Any help would be appreaciated.

How to send serial data from Arduino to Visual Studio C# with zedgraph and vice versa simultaniously

I'm working on a project to read analog data from Arduino and then display it in Visual C# with zedgraph. I have a start button on my GUI that starts the reading of serial data from Arduino. I can do that with private void read_Tick method that open the arduino port, read serial data, display data on zedgraph, and then close the arduino for every 1 second. If you having a trouble understanding my words, here's the method:
private void read_Tick(object sender, EventArgs e)
{
try
{
arduino.Open();
LineItem kurvaKonsentrasi = zedGraphKonsentrasi.GraphPane.CurveList[0] as LineItem;
IPointListEdit listKonsentrasi = kurvaKonsentrasi.Points as IPointListEdit;
double time = (Environment.TickCount - timeStart) / 1000.0;
float dataKonsentrasi = float.Parse(arduino.ReadLine(), CultureInfo.InvariantCulture.NumberFormat);
listKonsentrasi.Add(time,Convert.ToDouble(dataKonsentrasi));
arduino.Close();
Scale xScale = zedGraphKonsentrasi.GraphPane.XAxis.Scale;
if (time > xScale.Max - xScale.MajorStep)
{
xScale.Max = time + xScale.MajorStep;
xScale.Min = xScale.Max - 30.0;
}
zedGraphKonsentrasi.AxisChange();
zedGraphKonsentrasi.Invalidate();
}
catch (Exception fail)
{
if (arduino.IsOpen)
{
arduino.Close();
}
}
}
This method is called when I clicked start button. So, my problem is, I want to send string data "on" when I click start button. This string data is used for ordering Arduino to move the servo I attached with this code in void loop() before the analog readings.
if(Serial.available()>0){
start = Serial.read();
if(start == "on"){
servoMotor.write(40);
}
}
I know there's something wrong with what I'm doing because I cant start the servo. Can you give me advice what should I do to make the Visual C# send the command to arduino to start the servo once then arduino start the readings and then Visual C# read it?
Serial.read() only returns a single byte, so you're not going to get "on". You'll get "o" the first time, and if you read it again, you'll get "n."
If you follow the "on" with a "\n" (new line character), you can do something like this:
char command[3];
if (Serial.available() > 0) {
int bytesRead = Serial.readBytesUntil('\n', command, 2);
command[2] = '\0';
if strcmp(command, "on") == 0) {
servoMotor.write(40);
}
}

Generate a sliding windows on a temporary pushed buffer in C#

I get some big chunks of audio samples pushed by the sound card.
I want to start from the beginning of the chunk and apply a function on part of the chunk. This function is checking zero-crossing rate.
I thought of copying a part of the chunk to temporary buffer - something like a shifted buffer. And always pushing new sample to the temp buffer. I don't want to miss samples comes from the sound card(so that the previous bytes that have not been checked yet won't run over).
What is the best way to generate such a case?
This is how my event of audio samples from sound card look like:
void myWaveIn_DataAvailable(object sender, WaveInEventArgs e)
{
for (int index = 0; index < e.BytesRecorded; index += 2)//Here I convert in a loop the stream into floating number samples
{
short sample = (short)((e.Buffer[index + 1] << 8) |
e.Buffer[index + 0]);
SamplesBuf.Add = (sample / 32768f);//IEEE 32 floating number
}
//Do some processing on SamplesBuf
}

Inserting adjustable delay on each Input Source

I'm currently using Naudio to create a mixer with multiple inputs and multiple outputs.
For each input, while the audio is playing, I would like to be able to add a sample sized delay whenever I choose to.
The effect will be similar to pausing for, say 100 samples, and then playing again.
For example, a mixingSampleProvider is currently playing audio to output Channel 5, using multiplexingSampleProvider. On a certain button click, i would like to delay mixingSampleProvider by 200 samples, before it continues playing from the point it paused for a moment.
I would like to know if it's possible to do so, and what options can be looked at to achieve this effect.
Edit:
The specific problem which requires fixing, would be the knowledge gap I have in inserting Zeros to the buffer, while pushing all the rest of the samples back, while audio is playing. Here, I'm not looking for code to be written, but am looking for resources to attempt to create a new class to solve this issue. Or whether it is even possible at all.
Edit 2: Code I have tried (failed)
public int Read(float[] buffer, int offset, int count)
{
int sampleRead = source.Read(buffer,offset,count);
int delaySamples = Math.Min(count, DelayBySamples - delayPos);
float[] copyBuffer = buffer;
for (int n = 0; n < delaySamples;n++ )
{
buffer[offset + n] = 0;
}
for (int n = 0; n < sampleRead;n++ )
{
buffer[offset + delaySamples + n] = copyBuffer[offset+n];
}
delayPos += delaySamples;
sampleRead += delaySamples;
return sampleRead;
}
You should implement this by creating your own custom ISampleProvider that wraps each input to your mixer (Decorator pattern). Then have a method that tells it to insert n samples of silence. Then in the Read method of your SampleProvider if silence is required, then put up to the desired number of silent samples into the read buffer. And when the pause finishes, start returning samples from the source provider again.
You can have a look at the source code to the OffsetSampleProvider for inspiration, which allows you to add a specified number of silence samples at the start of your stream.

Categories

Resources