Question

EDIT:FINAL SOLUTION:

Seeing as the final solution was buried in comments, I'll put it here for future viewers.

My problem is that the signal I was using to stop an action included "r", also the command for stop (I thought I was being clever, combining my "left" command and "stop" command). The C++ (arduino) code read each caharacter individually, hence stopping the signal altogether, not just the one which I wanted.

Thankyou to dbasnett for poitning this out :)

Alrighty, hi all, this is my final question for this latest project of mine. The idea, simply, was to make a program to control an RC car through an arduino. It works!!! (with only a small bug).

Simply, I use the arrow keys or WASD to control the program. It sends a signal through a Serial Port to the arduino, which has a few functions in it for interpreting the signal. You have a total of 9 signal that can be sent; one for each direction, one to stop each directional input (e.g. left makes car point wheels left, stop-left points the wheels straight ahead).

The PROBLEM IS: When I go both FORWARD (or reverse) and LEFT (or right), if I change DIRECTION (left/right), it stops all together. I've spent most of the project trying to work this out, and I just can't see what Im doing wrong.

so, my code:

Imports System.IO.Ports
Imports System.IO
Imports System.Threading

Public Class Form1

    Shared _continue As Boolean
    Shared _serialPort As SerialPort
    Shared lturn As Boolean
    Shared rturn As Boolean
    Shared keydelay As Integer = 0

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

        SerialPort1.PortName = "com3" 'change com port to match your Arduino port
        SerialPort1.BaudRate = 115200
        SerialPort1.DataBits = 8
        SerialPort1.Parity = Parity.None
        SerialPort1.StopBits = StopBits.One
        SerialPort1.Handshake = Handshake.None
        SerialPort1.Encoding = System.Text.Encoding.Default 'very important!

    End Sub

    Private Sub Form1_KeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles MyBase.KeyDown

        Dim bHandled As Boolean = False

        If SerialPort1.IsOpen Then
        Else
            SerialPort1.Open()
        End If

        Select Case e.KeyCode

            Case Keys.Right

                pbBgML.BackColor = Color.Transparent
                pbBgMR.BackColor = Color.Black
                SerialPort1.Write("d")

                e.Handled = True

            Case Keys.Left

                pbBgMR.BackColor = Color.Transparent
                pbBgML.BackColor = Color.Black
                SerialPort1.Write("a")

                e.Handled = True

            Case Keys.Up

                pbBgBC.BackColor = Color.Transparent
                pbBgTC.BackColor = Color.Black
                SerialPort1.Write("w")

                e.Handled = True

            Case Keys.Down

                pbBgTC.BackColor = Color.Transparent
                pbBgBC.BackColor = Color.Black
                SerialPort1.Write("s")

                e.Handled = True

            Case Keys.Space

                SerialPort1.Write("r")

                e.Handled = True

        End Select
    End Sub

    Private Sub Form1_KeyUp(ByVal sender As Object, ByVal e As KeyEventArgs) Handles Me.KeyUp

        Select Case e.KeyCode

            Case Keys.Right
                pbBgMR.BackColor = Color.Transparent
                SerialPort1.Write("dr")

            Case Keys.Left
                pbBgML.BackColor = Color.Transparent
                SerialPort1.Write("ar")

            Case Keys.Up
                pbBgTC.BackColor = Color.Transparent
                SerialPort1.Write("wr")

            Case Keys.Down
                pbBgBC.BackColor = Color.Transparent
                SerialPort1.Write("sr")

        End Select

    End Sub

End Class

Also, if you want it, the arduino code (in C++):

    // Car Control v. 0.2

int reversePin = 9;
int forwardPin = 8;
int leftPin = 10;
int rightPin = 11;

byte byteRead;
int time;

void forward(int time){
  digitalWrite(reversePin, HIGH);
  Serial.println("This is forward...");
  digitalWrite(forwardPin, LOW);
  delay(time);
}

void reverse(int time){
  digitalWrite(forwardPin, HIGH);
  Serial.println("This is reverse...");
  digitalWrite(reversePin, LOW);
  delay(time);
}

void left(int time){
  digitalWrite(rightPin, HIGH);
  Serial.println("This is left...");
  digitalWrite(leftPin, LOW);
  delay(time);
}

void right(int time){
  digitalWrite(leftPin, HIGH);
  Serial.println("This is right...");
  digitalWrite(rightPin, LOW);
  delay(time);
}

void off(){
  Serial.println("This is stop...");
  digitalWrite(leftPin, HIGH);
  digitalWrite(rightPin, HIGH);
  digitalWrite(reversePin, HIGH);
  digitalWrite(forwardPin, HIGH);
}

void setup() {
  // initialize the digital pins as an output.
  pinMode(rightPin, OUTPUT);
  pinMode(leftPin, OUTPUT);
  pinMode(forwardPin, OUTPUT);
  pinMode(reversePin, OUTPUT);

  Serial.begin(115200);
  Serial.print("\n\nStart...\n");
}

void loop() 
{
  //Turn everything off...
  if (Serial.available()) {
    /* read the most recent byte */
    byteRead = Serial.read();

    switch(byteRead)
   {
     case 'w':
     forward(5);
     break;

     case 'wr':
     digitalWrite(forwardPin, HIGH);
     break;

     case 's':
     reverse(5);
     break;

     case 'sr':
     digitalWrite(reversePin, HIGH);
     break;

     case 'a':
     left(5);
     break;

     case 'ar':
     digitalWrite(leftPin, HIGH);
     break;

     case 'd':
     right(5);
     break;   

     case 'dr':
     digitalWrite(rightPin, HIGH);
     break;

     case 'r':
     off();
     break;

    }
  }
}

Sorry for the huge blocks of text, but I simply have no idea where the issue is. Cheers guys.

Était-ce utile?

La solution

I can't help with the C code but the VB code could use a single byte for the control

<FlagsAttribute()> _
Enum ctrl As Byte
    stp = 0 'stop is no bits set
    frwd = 1 << 0 '1
    back = 1 << 1 '2
    left = 1 << 2 '4
    rght = 1 << 3 '8
    mask = 255
End Enum

Private _control(0) As ctrl

Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
    Select Case e.KeyCode
        Case Keys.Right
            _control(0) = _control(0) Or ctrl.rght
        Case Keys.Left
            _control(0) = _control(0) Or ctrl.left
        Case Keys.Up
            _control(0) = _control(0) Or ctrl.frwd
        Case Keys.Down
            _control(0) = _control(0) Or ctrl.back
    End Select
    'SerialPort1.Write(_control, 0, 1)
    Debug.WriteLine(_control(0))
End Sub

Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
    Select Case e.KeyCode
        Case Keys.Right
            _control(0) = _control(0) And (ctrl.mask Xor ctrl.rght)
        Case Keys.Left
            _control(0) = _control(0) And (ctrl.mask Xor ctrl.left)
        Case Keys.Up
            _control(0) = _control(0) And (ctrl.mask Xor ctrl.frwd)
        Case Keys.Down
            _control(0) = _control(0) And (ctrl.mask Xor ctrl.back)
    End Select
    'SerialPort1.Write(_control, 0, 1)
    Debug.WriteLine(_control(0))
End Sub

Autres conseils

I think your approach is a little off here.

I would suggest that you use a bit field to determine which input is being pressed with a different bit for each input (as each one is effectively independent).

Private _input As Integer = 0

Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
    'set the bit of the required input
    Select Case e.KeyCode
        Case Keys.Right
            _input = SetBit(_input, 0) '0001
        Case Keys.Left
            _input = SetBit(_input, 1) '0010
        Case Keys.Up
            _input = SetBit(_input, 2) '0100
        Case Keys.Down
            _input = SetBit(_input, 3) '1000
    End Select
    SerialPort1.Write(Convert.ToChar(_input))
End Sub

Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
    'clear the bit of the de-selected input
    Select Case e.KeyCode
        Case Keys.Right
            _input = ClearBit(_input, 0)
        Case Keys.Left
            _input = ClearBit(_input, 1)
        Case Keys.Up
            _input = ClearBit(_input, 2)
        Case Keys.Down
            _input = ClearBit(_input, 3)
    End Select
    SerialPort1.Write(Convert.ToChar(_input))
End Sub

Private Function SetBit(value As Integer, bit As Integer) As Integer
    ' Create a bitmask with the 2 to the nth power bit set:
    Dim mask As Integer = CInt(2 ^ bit)
    ' Set the nth Bit:
    value = value Or mask
    Return value
End Function

Private Function ClearBit(value As Integer, bit As Integer) As Integer
    ' Create a bitmask with the 2 to the nth power bit set:
    Dim mask As Integer = CInt(2 ^ bit)
    ' Clear the nth Bit:
    value = value And Not mask
    Return value
End Function

You then need to do the opposite in the C++ code (which should be much more elegant) and check for invalid key combinations (e.g. forward and backward together)

Ideally you would want to pass a Byte to the serial port no a character, but I have tried to keep it as similar as possible

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top