apache 发表于 2012-12-23 22:22:20

我的wifi小车

本帖最后由 apache 于 2012-12-23 22:24 编辑

    前端时间发过一个帖子,初步介绍了下小车。这几天基本把程序部分写好了。这里贴出协议和小车源码,希望对和我一样喜欢DIY小车的同学有所帮助。
    先说协议部分。协议使用了谷歌的Protocol Buffers进行定义。这样做有如下优缺点:
优点:
1、将数据处理与逻辑分离,使开发者不用关心繁琐的打解包过程,将更多注意力专注到业务逻辑上。
2、谷歌提供了通过proto定义文件生成多种语言的IO类的工具(protoc)
缺点:
1、略微优点浪费存储空间- -!
协议定义文件如下:
enum CTRL_CMD {
    LINE_MOVE_CMD = 100;
    MOVE_CMD = 101;
    SERVO_CTRL_CMD = 102;
    LED_CTRL_CMD = 103;
}
enum MOTOR_DIR {
    FORWARD_DIR = 0;
    BACKWARD_DIR = 1;
    STOP_DIR = 2; // 已停止
}
enum SELECT_SERVO {
    HORIZONTAL_SERVO = 0;
    VERTICAL_SERVO = 1;
    BOTH_SERVO = 2;
}
enum SET_LED {
    LED_ON = 0;
    LED_OFF = 1;
}
message Head {
    required fixed32 cmd = 1;
    required fixed32 body_len = 2;
}
message LineMove {
    required int32 dir = 1;
    required int32 speed = 2;
}
message Move {
    required int32 left_dir = 1;
    required int32 left_speed = 2;
    required int32 right_dir = 3;
    required int32 right_speed = 4;
}
message ServoCtrl {
    required int32 select = 1;
    required int32 angle = 2;
}
message LedCtrl {
    required int32 flag = 1;
}

分别通过protoc.jar和protoc.exe生成Arduino使用的c文件和上位机程序使用的Python IO类


下面是wificar.h和wificar.c的源码
#ifndef WIFI_CAR
#define WIFI_CAR
#include "Arduino.h"
extern "C" {
#include "protocol.h"
}
typedef struct Head Head;
typedef struct LineMove LineMove;
typedef struct Move Move;

#define YES 1
#define NO 0

#define HEAD_SIZE 11
#define MAX_BUFFER_SIZE 64
#define PWM_ENA_PIN 3
#define PWM_ENB_PIN 5
#define PWM_IN1_PIN 7
#define PWM_IN2_PIN 8
#define PWM_IN3_PIN 11
#define PWM_IN4_PIN 12
#define WAVE_TRIG_PIN 4
#define WAVE_ECHO_PIN 2
#define LED_PIN 13
#define V_SERVO_PIN 9
#define H_SERVO_PIN 10
#define V_REF_ANGLE 100
#define H_REF_ANGLE 86
#define MAX_HSERVO_ANGLE (180 - V_REF_ANGLE)
#define MAX_VSERVO_ANGLE (180 - H_REF_ANGLE)
#define MIN_HSERVO_ANGLE (-V_REF_ANGLE)
#define MIN_VSERVO_ANGLE (-H_REF_ANGLE)

#define SET_PINS_MODE(PINS, MODE) \
    do { \
      for(int i = 0; i < sizeof(PINS); i++) \
            pinMode(PINS, MODE); \
    }while(0)
   
#define SET_LEFT_PWM(SPEED) analogWrite(PWM_ENB_PIN, (SPEED))
#define SET_RIGHT_PWM(SPEED) analogWrite(PWM_ENA_PIN, (SPEED))
#define SET_DIR(DIR, XPIN, YPIN) \
    do { \
      if(DIR != _STOP_DIR) {\
            digitalWrite(XPIN, DIR); \
            digitalWrite(YPIN, !DIR); \
      }else {\
            digitalWrite(XPIN, 0); \
            digitalWrite(YPIN, 0); \
      } \
    }while(0)
   
#define SET_LEFT_DIR(DIR) SET_DIR(DIR, PWM_IN3_PIN, PWM_IN4_PIN)
#define SET_RIGHT_DIR(DIR) SET_DIR(DIR, PWM_IN1_PIN, PWM_IN2_PIN)

#define SET_MOTOR(LSPD, LDIR, RSPD, RDIR) \
    do { \
      SET_LEFT_PWM((LSPD)); \
      SET_RIGHT_PWM((RSPD)); \
      SET_LEFT_DIR((LDIR)); \
      SET_RIGHT_DIR((RDIR)); \
    }while(0)

#define ROTATE_HSERVO(ANGLE) hservo.write(H_REF_ANGLE + (ANGLE))
#define ROTATE_VSERVO(ANGLE) vservo.write(V_REF_ANGLE + (ANGLE))
   
#define DEBUG
#ifdef DEBUG
#define DBG(msg) Serial.println(msg)
#else
#define DBG(msg)
#endif

#endif


#include <Servo.h>
#include "wificar.h"

static Servo hservo, vservo;
static int g_hcur_angle = 0, g_vcur_angle = 0;
static uint8_t g_waiting_head = YES;
static Head g_head;

void init_pin()
{
    uint8_t opins[] = {
      PWM_ENA_PIN, PWM_IN1_PIN, PWM_IN2_PIN,
      PWM_ENB_PIN, PWM_IN3_PIN, PWM_IN4_PIN,
      WAVE_TRIG_PIN, LED_PIN
    };
    uint8_t ipins[] = {
      WAVE_ECHO_PIN
    };
    SET_PINS_MODE(opins, OUTPUT);
    SET_PINS_MODE(ipins, INPUT);
    pinMode(WAVE_TRIG_PIN, OUTPUT);
    pinMode(WAVE_ECHO_PIN, INPUT);
}
void init_servo()
{
        vservo.attach(V_SERVO_PIN);
        hservo.attach(H_SERVO_PIN);
        vservo.write(V_REF_ANGLE);
        hservo.write(H_REF_ANGLE);
}
void setup()
{
    Serial.begin(9600);
    Serial.flush();
    init_pin();
    init_servo();
}

inline void on_line_move(uint8_t *buffer)
{
    LineMove lnmove;
   
    LineMove_read_delimited_from(buffer, &lnmove, 0);
    SET_MOTOR(lnmove._speed, lnmove._dir, lnmove._speed, lnmove._dir);
}

inline void on_move(uint8_t *buffer)
{
    Move move;
   
    Move_read_delimited_from(buffer, &move, 0);
    SET_MOTOR(move._left_speed, move._left_dir, move._right_speed, move._right_dir);
}
inline void on_servo_ctrl(uint8_t *buffer)
{
    ServoCtrl servo_ctrl;
    ServoCtrl_read_delimited_from(buffer, &servo_ctrl, 0);
    if(servo_ctrl._select == _HORIZONTAL_SERVO || servo_ctrl._select == _BOTH_SERVO)
    {
      g_hcur_angle += servo_ctrl._angle;
      if(g_hcur_angle > MAX_HSERVO_ANGLE || g_hcur_angle < MIN_HSERVO_ANGLE)
            g_hcur_angle -= servo_ctrl._angle;
      ROTATE_HSERVO(g_hcur_angle);
    }
    if(servo_ctrl._select == _VERTICAL_SERVO || servo_ctrl._select == _BOTH_SERVO)
    {
      g_vcur_angle += servo_ctrl._angle;
      if(g_vcur_angle > MAX_VSERVO_ANGLE || g_vcur_angle < MIN_VSERVO_ANGLE)
            g_vcur_angle -= servo_ctrl._angle;
      ROTATE_VSERVO(g_vcur_angle);
    }
}
inline void on_led_ctrl(uint8_t *buffer)
{
    LedCtrl led_ctrl;
    LedCtrl_read_delimited_from(buffer, &led_ctrl, 0);
    if(led_ctrl._flag == _LED_ON)
    {
      digitalWrite(LED_PIN, HIGH);
    }
    else
    {
      digitalWrite(LED_PIN, LOW);
    }
}
inline void proto_master(uint8_t *buffer)
{
    switch(g_head._cmd)
    {
    case _LINE_MOVE_CMD:
      on_line_move(buffer);
      break;
    case _MOVE_CMD:
      on_move(buffer);
      break;
    case _SERVO_CTRL_CMD:
      on_servo_ctrl(buffer);
      break;
    case _LED_CTRL_CMD:
      on_led_ctrl(buffer);
      break;
    default:
      break;
    }
    Serial.flush();
}

inline void recv_package()
{
    int nbytes;
    uint8_t buffer;
   
    nbytes = Serial.available();
    if(g_waiting_head == YES)
    {
      if(nbytes >= HEAD_SIZE)
      {
            Serial.readBytes((char *)buffer, HEAD_SIZE);
            Head_read_delimited_from(buffer, &g_head, 0);
            g_waiting_head = NO;
      }
    }
    else
    {
      if(nbytes >= g_head._body_len)
      {
            Serial.readBytes((char *)buffer, g_head._body_len);
            proto_master(buffer);
            g_waiting_head = YES;
      }
    }
}
void loop()
{
    recv_package();
}


完整代码见附件:

上位机程序使用Python+PyQt4+Python OpenCv开发,因为通过Py2exe转成exe程序后比较大,这里暂时不发(后续贴出网盘下载路径)
http://v.youku.com/v_show/id_XNDkyMjAxMjA0.html

laoliu1982 发表于 2012-12-23 23:00:28

只能说niubility了,真是感兴趣,真是没时间弄啊

johnsonzzd 发表于 2012-12-24 15:53:56

Protocol Buffers是个好东西

伊宁 发表于 2012-12-27 16:22:07

请问楼主的wifi小车的硬件配置是什么,用的是arduino 1.0的编译器么?麻烦给个链接学习一下???

lomter 发表于 2013-2-15 15:21:09

楼主您好!首先祝您新年快乐
这个程序看了半天没看懂 您能否说下硬件接口的连接呢?谢谢

冷箭一霰 发表于 2013-6-20 22:43:32

需要WIFI视频模块可以找我哦,我是专门搞WIFI视频模块的,可以控制四轴,飞机等,进行航拍,这是模块地址:http://item.taobao.com/item.htm?spm=a1z10.1.w4004-1808600977.33.ATCVTG&id=18834002636

长青树 发表于 2014-6-16 11:19:42

非常感谢楼主的分享 能把上位机的程序分享下吗
页: [1]
查看完整版本: 我的wifi小车