1. 程式人生 > >吃飽了撐著的系列-近防炮轉向系統模擬

吃飽了撐著的系列-近防炮轉向系統模擬

本猿是球迷動漫迷歌迷軍迷,反正就是很迷

今日吃飽了撐在午睡的時候冒出這麼一個靈感然後動手造了個近防炮

主要是臨近2018珠海航展了我挺激動的

然後就從實驗室的邊角料裡誕生了這麼一個

沒火控雷達沒開火系統沒彈藥沒底座只會轉

莫得感情也莫得傷害的近防支架

我們真的有控制系統啦!

江湖規矩,上設計思路:

板子是Arduino UNO的,對應的開發環境自然是Arduino的那個Genuino

兩個舵機Servo,一大一小

支架什麼的根據自己的模型打造吧(差點忘了我也算模型迷吧,這個系統本來想裝在戰列艦模型上的,先驗證一下)

一開始還想再加個舵機控制橡皮筋發射的

不過感覺加了反正也參不了展,也莫得國家願意下單預訂多少套去對抗YJ系列(而且也打不過)

順便講講舵機怎麼連

這種Servo有三根顏色不同的線,一般中間的是紅色的,邊上有時候是黑線和黃線有時候又是棕線和黃線

顏色更深的一般是黑線一樣的GND吧,可以先試試

紅線連5V黑線連GND,另外一根則是連到Arduino的一個介面上用於控制

本系統的大舵機控制水平方向上的轉動,小舵機控制垂直方向上的傾角

大舵機控制線連到介面9,小舵機連到介面6

用麵包板共用5V和GND

然後串列埠連線到宿主機,待會兒要拿串列埠通訊的(WiFi可以麼?當然ojbk,不過串列埠更可靠,哪有拿WiFi控制這麼強悍的武器的)

如果連線正確了,就可以先開發一下開發板程式了:

#include <Servo.h>

Servo myservo;          // 大舵機
Servo myservo2;         // 小舵機
int pos = 0;            // 大舵機角度
int pos2 = 0;           // 小舵機角度
String comdata = "";    // 接收到的串列埠資料

void setup() {
  Serial.begin(9600);   // 串列埠波特率為9600
  myservo.attach(9);    // 大舵機用介面9控制
  myservo2.attach(6);   // 小舵機用介面6控制
}

void loop() {
  // 監聽串列埠訊息
  while(Serial.available() > 0){
    comdata += char(Serial.read());
    delay(2);
  }

  // 處理資料
  if(comdata.length() > 0){
    Serial.println("Get rangle:" + comdata);
    int R = comdata.toInt();

    // 大於400的值認為是小舵機的指令
    if(R > 400){
      R -= 400;
      if(R > pos2){
        for(;pos2 < R;pos2++){
          myservo2.write(pos2);
          delay(15);
        }
      }
      else if(R < pos2){
        for(;pos2 > R;pos2--){
          myservo2.write(pos2);
          delay(15);
        }
      }
      else{
        // no action
      }
    }
    
    // 小於400的值認為是大舵機的指令
    else{
      if(R > pos){
        for(;pos < R;pos++){
          myservo.write(pos);
          delay(15);
        }
      }
      else if(R < pos){
        for(;pos > R;pos--){
          myservo.write(pos);
          delay(15);
        }
      }
      else{
        // no action
      }
    }
    
    // 清空接收變數
    comdata = "";
  }
}

Arduino的開發環境自帶串列埠監視器,可以先在那除錯一下能不能控制轉動

然後就是主機上的轉動控制程式啦

開發這個程式其實本來也是想作為一個Server然後能中繼一下手機APP發來的控制指令

好吧我一開始也想拿手機控制我的近防炮的

軍火也隨一下移動端大流嘛

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;

namespace FiregunServer
{
    public partial class Form1 : Form
    {
        // 串列埠變數
        private static SerialPort serialPort = null;

        // 炮臺角度變數
        private int horizen;   // 水平角度
        private int vertical;  // 垂直角度

        // 支援項
        private const int DELAY_TIME = 25;

        public Form1()
        {
            InitializeComponent();
            horizen = 0;
            vertical = 20;
        }

        public void launch(string msg)
        {
            byte[] sendData;
            sendData = System.Text.Encoding.Default.GetBytes(msg);

            if (serialPort == null)
            {
                serialPort = new SerialPort("COM5", 9600, Parity.None, 8, StopBits.One);
                serialPort.ReadBufferSize = 1024;
                serialPort.WriteBufferSize = 1024;
            }

            if (!serialPort.IsOpen)
            {
                serialPort.Open();
            }

            //傳送資料
            serialPort.Write(sendData, 0, sendData.Length);
        }

        // 水平角度增加
        private void button1_Click(object sender, EventArgs e)
        {
            left();
        }

        // 水平角度減少
        private void button3_Click(object sender, EventArgs e)
        {
            right();
        }

        // 垂直角度增加
        private void button2_Click(object sender, EventArgs e)
        {
            up();
        }

        // 垂直角度減少
        private void button4_Click(object sender, EventArgs e)
        {
            down();
        }

        // 炮臺往左
        private void left()
        {
            if (horizen < 180)
            {
                horizen++;
                textBox1.Text = horizen + "";
            }
            launch(horizen + "");
            textBox3.AppendText("水平:" + horizen + "\r\n");
        }

        // 炮臺往右
        private void right()
        {
            if (horizen > 0)
            {
                horizen--;
                textBox1.Text = horizen + "";
            }
            launch(horizen + "");
            textBox3.AppendText("水平:" + horizen + "\r\n");
        }

        // 炮口太高
        private void up()
        {
            if (vertical < 180)
            {
                vertical++;
                textBox2.Text = vertical + "";
            }
            launch((vertical + 400) + "");
            textBox3.AppendText("垂直:" + vertical + "\r\n");
        }

        // 炮口降低
        private void down()
        {
            if (vertical > 0)
            {
                vertical--;
                textBox2.Text = vertical + "";
            }
            launch((vertical + 400) + "");
            textBox3.AppendText("垂直:" + vertical + "\r\n");
        }

        // 快速定位動作
        public void quickLocate(int H, int V)
        {
            // 檢驗值
            if (H < 0 || H > 180 || V < 0 || V > 90)
            {
                textBox4.Text = "0";
                textBox5.Text = "0";
                return;
            }

            // 確定轉動距離
            int dH, dV;
            dH = H - horizen;
            dV = V - vertical;

            // 轉動水平角度
            if (dH > 0)
            {
                for (int i = 0; i < dH; i++)
                {
                    left();
                    Delay(DELAY_TIME);
                }
            }
            else
            {
                for (int i = 0; i < -dH; i++)
                {
                    right();
                    Delay(DELAY_TIME);
                }
            }

            // 轉動垂直角度
            if (dV > 0)
            {
                for (int i = 0; i < dV; i++)
                {
                    up();
                    Delay(DELAY_TIME);
                }
            }
            else
            {
                for (int i = 0; i < -dV; i++)
                {
                    down();
                    Delay(DELAY_TIME);
                }
            }
        }

        // 快速定位
        private void button5_Click(object sender, EventArgs e)
        {
            // 獲取設定值
            int H = int.Parse(textBox4.Text);
            int V = int.Parse(textBox5.Text);
            quickLocate(H, V);
        }

        // 延遲函式
        public static void Delay(int milliSecond)
        {
            int start = Environment.TickCount;
            while (Math.Abs(Environment.TickCount - start) < milliSecond)//毫秒
            {
                Application.DoEvents();//可執行某無聊的操作
            }
        }

        // 炮口復位
        private void button6_Click(object sender, EventArgs e)
        {
            quickLocate(0, 20);
        }

    }
}

程式介面在上面有哦,背景是我們的校徽嘿嘿

 

今天學到了什麼呢?

1、Arduino的串列埠開發和舵機控制開發

2、C#的串列埠程式開發

3、人別想太多

4、男人的快樂很簡單


新增一下效果:

快速定位

自動復位