极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 12923|回复: 6

我的wifi小车

[复制链接]
发表于 2012-12-23 22:22:20 | 显示全部楼层 |阅读模式
本帖最后由 apache 于 2012-12-23 22:24 编辑

    前端时间发过一个帖子,初步介绍了下小车。这几天基本把程序部分写好了。这里贴出协议和小车源码,希望对和我一样喜欢DIY小车的同学有所帮助。
    先说协议部分。协议使用了谷歌的Protocol Buffers进行定义。这样做有如下优缺点:
优点:
1、将数据处理与逻辑分离,使开发者不用关心繁琐的打解包过程,将更多注意力专注到业务逻辑上。
2、谷歌提供了通过proto定义文件生成多种语言的IO类的工具(protoc)
缺点:
1、略微优点浪费存储空间- -!
协议定义文件如下:
[pre lang="pb" line="1" file="Protocol.proto"]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;
}[/code]

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


下面是wificar.h和wificar.c的源码
[pre lang="C" line="1" file="wificar.h"]#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
[/code]

[pre lang="arduino" line="1" file="wificar.ino"]#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[MAX_BUFFER_SIZE];
   
    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();
}
[/code]

完整代码见附件:

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

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1 +1 收起 理由
幻生幻灭 + 1 很强大!期待后续

查看全部评分

回复

使用道具 举报

发表于 2012-12-23 23:00:28 | 显示全部楼层
只能说niubility了,真是感兴趣,真是没时间弄啊
回复 支持 反对

使用道具 举报

发表于 2012-12-24 15:53:56 | 显示全部楼层
Protocol Buffers是个好东西
回复 支持 反对

使用道具 举报

发表于 2012-12-27 16:22:07 | 显示全部楼层
请问楼主的wifi小车的硬件配置是什么,用的是arduino 1.0的编译器么?麻烦给个链接学习一下???
回复 支持 反对

使用道具 举报

发表于 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 | 显示全部楼层
非常感谢楼主的分享 能把上位机的程序分享下吗
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-4-24 12:30 , Processed in 0.044075 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表