插叙: 作为一个Python零基础的咸鱼大学生,7.4和7.5趁着休息的时间笼统看了一遍北理工的mooc国家精品课.觉得理解还是很浅,现在学长推荐下买了本<Python学习手册>,上下两册很厚,等啃完以后可以在这里以初学者的角度写一篇测评.
2020.7.6
今天的话老板让另一位学长开始教我这个项目的硬件部分,通俗的话来说就是让机器小车跑起来,但往往看似简单的部分会有意想不到的小问题.
由于临近午饭时间了,学长只给我介绍了机器小车的大致组成和连线部分.这里我可以凭着印象稍微总结一下:
首先的25V的供电电源通过一个变压器降成5V供电给左右轮的两个板子,两个板子分别控制电机从而控制左右轮子的转动.接线部分其他模块都已经是固定连接过了,包括电源的开关,左右轮的开关,电机的连接等.我需要理解分配的是左右轮方向和速度模块的连接,其实也很简单.就是分别用三根波导线连接左右轮控制板和Mega 2560上的引脚.左轮对应2560上8,22,23上的引脚;右轮对应9,24,25上的引脚;8,9控制生成PWM从而控制占空比来改变速度;22-25改变轮子转动的方向.
学长怕我忘了怎么连,给了我一个测试的元件,上面三根线的分布即对应左右轮板子上的引脚:黑红线对应0或1从而控制轮子的正反转;另一个黄线自然是控制PWM波的生成.以下配个图.
2020.7.7
预习了一下下Arduino,发现我上学期学的单片机课上用的ICCAVR编译软件相较之下麻烦了许多.但当时刚接触单片机,用最原始的语言自己多写一写也是有好处的.
2020.7.8
今天的目标是用电脑控制机器小车"跑"起来.
第一步:用Arduino写机器小车的基础运动,以下贴上代码,通俗易懂就不再多解释.
Serial.h:
#include<Arduino.h>
void init_test();
void Forward(int speed);
void Backward(int speed);
void TurnLeft(int speed, int cha);
void TurnRight(int speed, int cha);
void TurnLeft90(int speed);
void TurnRight90(int speed);
void Stop();
Serial.cpp:
#include"Serial.h"
void init_test()
{
pinMode(8,OUTPUT); //左轮速度模拟量
pinMode(9,OUTPUT); //右轮速度模拟量
pinMode(22,OUTPUT);//左轮方向控制
pinMode(23,OUTPUT);
pinMode(24,OUTPUT);//右轮方向控制
pinMode(25,OUTPUT);
Serial.begin(9600);//Baud rate
}
void Stop()
{
digitalWrite(22,0);
digitalWrite(23,0);
digitalWrite(24,0);
digitalWrite(25,0);
}
void Forward(int speed)
{
digitalWrite(22,0);
digitalWrite(23,1);
digitalWrite(24,0);
digitalWrite(25,1);
analogWrite(8,speed);
analogWrite(9,speed-3);
}
void Backward(int speed)
{
digitalWrite(22,1);
digitalWrite(23,1);
digitalWrite(24,1);
digitalWrite(25,1);
analogWrite(8,speed);
analogWrite(9,speed-3);
}
void TurnLeft(int speed, int cha)
{
digitalWrite(22,0);
digitalWrite(23,1);
digitalWrite(24,0);
digitalWrite(25,1);
analogWrite(8,speed-cha);//左轮速度小于右轮速度
analogWrite(9,speed+cha);
}
void TurnRight(int speed, int cha)
{
digitalWrite(22,0);
digitalWrite(23,1);
digitalWrite(24,0);
digitalWrite(25,1);
analogWrite(8,speed+cha);//右轮速度小于左轮速度
analogWrite(9,speed-cha);
}
void TurnLeft90(int speed)
{
digitalWrite(22,1);
digitalWrite(23,1);
digitalWrite(24,0);
digitalWrite(25,1);
analogWrite(8,speed);
analogWrite(9,speed);
}
void TurnRight90(int speed)
{
digitalWrite(22,0);
digitalWrite(23,1);
digitalWrite(24,1);
digitalWrite(25,1);
analogWrite(8,speed);
analogWrite(9,speed);
}
Test(主函数):
#include"Serial.h"
String comdata="";
int speed=30;
int speed_span=30;
int cha=15;
void setup()
{
init_test();
}
void loop()
{
//Forward(speed);
//Backward(speed);
//TurnLeft(speed,cha);
//TurnRight(speed,cha);
//TurnLeft90(speed_span);
//TurnRight90(speed_span);
delay(2000);
while(1)
{
Stop();
}
//TurnRight(speed,cha);
while(Serial.available())
{
comdata+=char(Serial.read());
delay(2);
}
switch(comdata[0])
{
case 'F':
Forward(speed);
Serial.print(comdata);
comdata="";
break;
case 'S':
Stop();
Serial.print(comdata);
comdata="";
break;
case 'B':
Backward(speed);
Serial.print(comdata);
comdata="";
break;
case 'l':
TurnLeft(speed,cha);
Serial.print(comdata);
comdata="";
break;
case 'r':
TurnRight(speed,cha);
Serial.print(comdata);
comdata="";
break;
case 'L':
TurnLeft90(speed_span);
Serial.print(comdata);
comdata="";
break;
case 'R':
TurnRight90(speed_span);
Serial.print(comdata);
comdata="";
break;
default:
comdata="";
Serial.print(comdata);
break;
}
}
在这部分我遇到有个问题应该具有普遍性,就是init_test这个函数一开始我使用的是init,运行后机器小车是不会动的,问题很简单,因为init在Arduino里是内嵌函数名,已经拥有了它自己的功能,所以不能被开发者定义.
其实到这里,机器小车已经可以动了,但功能还不完善.
第二步:写一个基础代码实现电脑端传输字符F/B/S/R/L/r/l来操控小车的运动
为什么要写这一个基础代码呢?我理解的项目目的是经过电脑端识别出小车前方图像,然后判断应该前进,后退,左转,右转,原地左转还是原地右转.所以这个基础代码是很重要的组成部分.
一开始学长拷了他写好的一个C++串行通讯的代码给我,改了改其中两行操作语句,直接就实现了这个功能.可后续的图像处理肯定是使用Python来进行的,要是用C++来实现这个功能,需要在后续总程序里用Python调用C++,这个反应起来没那么快.
所以我们着手开始研究Python的串行通讯实现,从万能的搜索引擎上进行检索,找了好几个基础代码,思路都是一样的,直接拷贝过来,发现机器小车并无任何反应.检索程序的问题肯定是使用交互式,于是打开Anaconda,一行行运行代码,神奇的事情发生了,功能实现了!但反过头在Anaconda里运行写好的Python文件程序却依旧毫无反应.不瞒大家说,这个非常简单的问题花了我们一个下午纠错,我们尝试过在语句末尾加sleep进行延时;尝试过用Notepad++进行编码,因为它可以调整不用的编码规则;尝试过用串口助手接收传输字符来验证.
最后到晚上,我们捋了捋思路,因为之前在基础语句里加了print函数,显示出来的结果是可以说明单片机收到了数据而且数据形式是对的,同时单片机上面RX/TX灯也闪烁了一下,更加印证了这一点.然后我们在交互端把代码一下子写完运行,也是不行的.这说明了代码本身思路肯定没问题.问题出在了Arduino上,在打开Arduino的串口的时候会重启,打开后需要等待重启完成.解决方法是在语句中间加一句sleep延时函数.
import serial
import time
ser=serial.Serial("COM3",9600)
time.sleep(2)
num=ser.write("F".encode())
print(num)
ch=ser.read(1)
print(ch)
2020.7.10
今天的任务并不烧脑,两个部分,一是将机器小车上的部件及连线初步整理固定一下;二自然就是测试小车实际执行每个指令的能力。
第一部分的话,我以前没有相关的经验,自己摸索了一下,先将电池和各种板在小车上固定一下,然后的话线比较乱,我就按左轮一部分,右轮一部分,分为默认连线和可调试连线两部分用塑料防盗线固定了一下。经过这些小步骤,至少我自己看起来是比较清晰明了了。
第二部分,是比较细致而不稳定的调试,我在连接电脑调试功能的时候就有发现,比如输入ForWard指令的时候,可能会因为某些内部的原因左右轮开始转动会有一个小的时间差;更偶尔的话甚至会出现某个轮子失灵的情况。这是暂时无法避免的。而我接下来的任务是逐个将前面写的命令传入单片机里,让小车在地面上实际跑动测试功能。首先前进后退应该是直线的,但我在设置左右路8,9引脚模拟量(对应速度大小)都为30的时候,在前进后退时会出现略微偏角的情况。我做的处理是将9的模拟量减去了3,也就是说,左右轮相同模拟量时,右轮会转的略微快一点点。接着左右转当然是可以直接实现的,由于还没有见到实际的管道路况,所以左右转角度并没有在今天进行调试。然后的话是原地左右转,通过前面的代码可以看见我是通用左轮反转右轮正转进行一个原地左转,右转同理,我本以为实际测试会出现一点问题,但没想到很顺利地通过了。
最后一个想要实现的是车轮抱死功能,其实在之前测试前进功能时我就发现这个功能可能按我的写法实现不了。之前我设定的测试前进代码是前进2s然后车轮抱死,可在车轮正转2s后,并没有抱死,而是随着惯性前进,我有用手转动车轮感受发现,车轮轴的阻尼感并没有那么强,而单片机内部写00好像也无法避免惯性。这点我想了许久也没法解决,后期等在管道中实际测试可以在硬件方面想点办法。
就这样,下周准备研究一下管道里的图像处理。