I'm using an Arduino Uno and breadboard for the first time and building my first actual robot. I have 2 servos controlling the x and y axis and attached a laser pointer to the end of it. My problem is not setting up the Arduino or anything, it's the getting the servos to move to a certain spot (wherever the mouse is) and then stopping until the mouse moves. I am coding this in Python and will gladly put in the code I am trying to use. (And the Arduino code) If you see anything wrong then please correct me. Thank you. Also the code isn't mine and I just found a cool video that had links to the code but when it get's to the point (wherever the mouse is) it won't stop and instead continue twisting up the wires that are connecting everything and supplying power.
#include<Servo.h>
Servo servoVer; //Vertical Servo
Servo servoHor; //Horizontal Servo
int x;
int y;
int prevX;
int prevY;
void setup()
{
Serial.begin(9600);
servoVer.attach(10); //Attach Vertical Servo to Pin 5
servoHor.attach(11); //Attach Horizontal Servo to Pin 6
servoVer.write(90);
servoHor.write(90);
}
void Pos()
{
if (prevX != x || prevY != y)
{
prevX.update;
prevY.update;
}
}
void loop()
{
if(Serial.available() > 0)
{
if(Serial.read() == 'X')
{
x = Serial.parseInt();
if(Serial.read() == 'Y')
{
y = Serial.parseInt();
Pos();
}
}
while(Serial.available() > 0)
{
Serial.read();
}
}
}
Arduino code ^^
import pygame as game
import time
import serial
import sys
game.init()
servo_comms = serial.Serial('COM5', 9600)
game.mouse.set_visible(True)
display = game.display.set_mode((180,180))
FPS = 60
watch = game.time.Clock()
black = (0,0,0)
def coordinate_graph(x,y):
display.fill((255,225,225))
game.draw.rect(display, (0,225,0), [x + 1, y ,5,2])
game.draw.rect(display, (0,225,0), [x - 2, y ,5,2])
game.draw.rect(display, (0,225,0), [x, y + 1 ,2,5])
game.draw.rect(display, (0,225,0), [x ,y - 2 ,2,5])
watch.tick(FPS)
def starter():
while True:
(x, y) = game.mouse.get_pos()
x = int(x)
y = int(y)
data = ("X{0:.0f}Y{1:.0f}Z".format(x, y))
servo_comms.write(data.encode())
for event in game.event.get():
if event.type == game.quit:
sys.exit(0)
font = game.font.SysFont('Ariel', 24)
img = font.render(data.encode(), True, black)
display.blit(img, (20, 20))
game.display.update()
coords(x, y)
starter()
Python code ^^
If you have any ideas on how to make the motors stop when they get to the coordinates on the 180 x 180 page, please help me. Thank you.
Related
I am trying to implement pan and zoom functions in my RTSP camera stream using Python. I want to be able to use my mouse wheel to zoom in and out from the video and click and drag to move the video around. However, I have not been able to find any tutorials on handling these mouse events in OpenCV.
Is there such a way or will I have resort to using keystrokes to pan and zoom my video?
You can use mouse event and imshow to achieve this function.
def mouse_event_callback(self, event,x,y,flags,param):
if event == cv2.EVENT_LBUTTONDOWN:
elif event == cv2.EVENT_MOUSEMOVE:
elif event == cv2.EVENT_LBUTTONUP:
elif event == cv2.EVENT_MOUSEWHEEL:
...
cv2.namedWindow('Test')
cv2.setMouseCallback('Test',self.mouse_event_callback)
while True:
cv2.imshow('Test',img)
The basic idea is deciding the scale changed every time on mouse wheel. After you get the current scale (v.s. origin image) and correct region of image you want to show on screen, you can get the position and length of rectangle on scaled image. So you can draw this rectangle on scaled image.
In my github,checking OnMouseWheel () and RefreshSrcView () in Fastest_Image_Pattern_Matching/ELCVMatchTool/ELCVMatchToolDlg.cpp may give what you want.
Although it's c++ code, but only imshow () and resize () are used. Focusing on how I change the scale and how the new rectangle to be draw in scaled image will be enough.
Effect:
Part of the code:
BOOL CELCVMatchToolDlg::OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)
{
POINT pointCursor;
GetCursorPos (&pointCursor);
ScreenToClient (&pointCursor);
// TODO: 在此加入您的訊息處理常式程式碼和 (或) 呼叫預設值
if (zDelta > 0)
{
if (m_iScaleTimes == MAX_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes++;
}
if (zDelta < 0)
{
if (m_iScaleTimes == MIN_SCALE_TIMES)
return TRUE;
else
m_iScaleTimes--;
}
CRect rect;
//GetWindowRect (rect);
GetDlgItem (IDC_STATIC_SRC_VIEW)->GetWindowRect (rect);//重要
if (m_iScaleTimes == 0)
g_dCompensationX = g_dCompensationY = 0;
int iMouseOffsetX = pt.x - (rect.left + 1);
int iMouseOffsetY = pt.y - (rect.top + 1);
double dPixelX = (m_hScrollBar.GetScrollPos () + iMouseOffsetX + g_dCompensationX) / m_dNewScale;
double dPixelY = (m_vScrollBar.GetScrollPos () + iMouseOffsetY + g_dCompensationY) / m_dNewScale;
m_dNewScale = m_dSrcScale * pow (SCALE_RATIO, m_iScaleTimes);
if (m_iScaleTimes != 0)
{
int iWidth = m_matSrc.cols;
int iHeight = m_matSrc.rows;
m_hScrollBar.SetScrollRange (0, int (m_dNewScale * iWidth - m_dSrcScale * iWidth) - 1 + BAR_SIZE);
m_vScrollBar.SetScrollRange (0, int (m_dNewScale * iHeight - m_dSrcScale * iHeight) - 1 + BAR_SIZE);
int iBarPosX = int (dPixelX * m_dNewScale - iMouseOffsetX + 0.5);
m_hScrollBar.SetScrollPos (iBarPosX);
m_hScrollBar.ShowWindow (SW_SHOW);
g_dCompensationX = -iBarPosX + (dPixelX * m_dNewScale - iMouseOffsetX);
int iBarPosY = int (dPixelY * m_dNewScale - iMouseOffsetY + 0.5);
m_vScrollBar.SetScrollPos (iBarPosY);
m_vScrollBar.ShowWindow (SW_SHOW);
g_dCompensationY = -iBarPosY + (dPixelY * m_dNewScale - iMouseOffsetY);
//滑塊大小
SCROLLINFO infoH;
infoH.cbSize = sizeof (SCROLLINFO);
infoH.fMask = SIF_PAGE;
infoH.nPage = BAR_SIZE;
m_hScrollBar.SetScrollInfo (&infoH);
SCROLLINFO infoV;
infoV.cbSize = sizeof (SCROLLINFO);
infoV.fMask = SIF_PAGE;
infoV.nPage = BAR_SIZE;
m_vScrollBar.SetScrollInfo (&infoV);
//滑塊大小
}
else
{
m_hScrollBar.SetScrollPos (0);
m_hScrollBar.ShowWindow (SW_HIDE);
m_vScrollBar.SetScrollPos (0);
m_vScrollBar.ShowWindow (SW_HIDE);
}
RefreshSrcView ();
return CDialogEx::OnMouseWheel (nFlags, zDelta, pt);
}
I'm currently trying to have a camera mounted on a pan tilt made of two micro servos track a face. My python code has been working and has been successfully identifying a face, but non of my servos have been moving while the Arduino is constantly flashing as if it is receiving input from the Python code. I haven't been able to get the servos to move according to my python code, but I have made simple code on the side to make sure the servos have good connections and they work fine on their own. I'm not sure what is wrong...
Python Code
import numpy as np6
import serial
import time
import sys
import cv2
arduino = serial.Serial('COM3', 9600)
time.sleep(2)
print("Connection to arduino...")
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
cap = cv2.VideoCapture(0)
while 1:
ret, img = cap.read()
cv2.resizeWindow('img', 500,500)
cv2.line(img,(500,250),(0,250),(0,255,0),1)
cv2.line(img,(250,0),(250,500),(0,255,0),1)
cv2.circle(img, (250, 250), 5, (255, 255, 255), -1)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3)
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),5)
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
arr = {y:y+h, x:x+w}
print (arr)
print ('X :' +str(x))
print ('Y :'+str(y))
print ('x+w :' +str(x+w))
print ('y+h :' +str(y+h))
xx = int(x+(x+h))/2
yy = int(y+(y+w))/2
print (xx)
print (yy)
center = (xx,yy)
print("Center of Rectangle is :", center)
data =(“X {0: f} Y {1: f} Z” .format (xx, yy))
print ("output = '" +data+ "'")
arduino.write(data.encode())
cv2.imshow('img',img)
k = cv2.waitKey(30) & 0xff
if k == 27:
break
Arduino Code
#include<Servo.h>
Servo servoVer; //Vertical Servo
Servo servoHor; //Horizontal Servo
int x;
int y;
int prevX;
int prevY;
void setup()
{
Serial.begin(9600);
servoVer.attach(5); //Vertical Servo to Pin 5
servoHor.attach(6); //Horizontal Servo to Pin 6
servoVer.write(90);
servoHor.write(90);
}
void Pos()
{
if(prevX != x || prevY != y)
{
int servoX = map(x, 600, 0, 70, 179);
int servoY = map(y, 450, 0, 179, 95);
servoX = min(servoX, 179);
servoX = max(servoX, 70);
servoY = min(servoY, 179);
servoY = max(servoY, 95);
servoHor.write(servoX);
servoVer.write(servoY);
}
}
void loop()
{
if(Serial.available() > 0)
{
if(Serial.read() == 'X')
{
x = Serial.parseInt();
if(Serial.read() == 'Y')
{
y = Serial.parseInt();
Pos();
}
}
while(Serial.available() > 0)
{
Serial.read();
}
}
}
One huge problem is the way you are using Serial.read. That function consumes the character out of the buffer. You don't get to read the same one twice. So let's say you send a 'Y'. The first if statement reads the Y out of the serial buffer and compares to 'X', that's false so it moves on. Then it reads something else from serial, probably a -1 if nothing is left to read. But it doesn't see the 'Y' because that was read in the first if.
What you need to do is to read from serial into a char variable and then use that char variable in your if statements.
char c = Serial.read();
if(c == 'X')...
... if (c == 'Y')...
I have a problem with updating the position of vertical lines simultaneously on plots using Chart.js. What I want to do is to draw vertical line in a specific x postion when mouse pointer is on another graph. The problem is that with the current code, after moving mouse pointer over one plot in the second I have plotted line but the plot doesn't refresh, thus after moving again pointer there are a bunch of other lines.
I was trying including update() option before drawing vertical lines which actually solves the problem but the whole chart is refreshed and it's very slow.
Thx for the help!
Chart.defaults.LineWithLine = Chart.defaults.scatter
Chart.controllers.LineWithLine = Chart.controllers.scatter.extend({
draw: function(ease) {
Chart.controllers.scatter.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.scales['y-axis-1'].top,
bottomY = this.chart.scales['y-axis-1'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 1.5;
ctx.strokeStyle = 'black';
ctx.stroke();
ctx.restore();
// get x value
var xValue = map(x, this.chart.chartArea.left, this.chart.chartArea.right, chainage_min, chainage_max);
if (this.chart == graph2) {
try {
// graph1.update() // drastically slows down
} finally {
//
}
var activePoint = graph2.tooltip._active[0],
ctx2 = graph1.ctx,
x = graph1.scales['x-axis-1'].getPixelForValue(xValue)
topY = graph1.scales['y-axis-1'].top,
bottomY = graph1.scales['y-axis-1'].bottom;
// draw line
ctx2.save();
ctx2.beginPath();
ctx2.moveTo(x, topY);
ctx2.lineTo(x, bottomY);
ctx2.lineWidth = 2.0;
ctx2.strokeStyle = 'black';
ctx2.stroke();
ctx2.restore();
} else if (this.chart == graph1) {
try {
//graph2.update() // drastically slows down
} finally {
//
}
var activePoint = graph1.tooltip._active[0],
ctx2 = graph2.ctx,
x = graph2.scales['x-axis-1'].getPixelForValue(xValue)
topY = graph2.scales['y-axis-1'].top,
bottomY = graph2.scales['y-axis-1'].bottom;
// draw line
ctx2.save();
ctx2.beginPath();
ctx2.moveTo(x, topY);
ctx2.lineTo(x, bottomY);
ctx2.lineWidth = 2.0;
ctx2.strokeStyle = 'black';
ctx2.stroke();
ctx2.restore();
}
}
}
})
function map(value, start1, stop1, start2, stop2) {
return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1))
}
I am attempting to import two motors onto my pyboard in micropython that are connected to my DFRobot DC Quad Motor Shield. Example code from them is written in Arduino and I cannot translate. Attached is my previous code that did not work and the motor shield over view with its speeds and connections.
Any help is appreciated!
Code Previously Written
Board Overview
Here is what I have
i2c = machine.I2C(scl=machine.Pin('Y9'), sda=machine.Pin('Y10'))
motors = motor.DCMotors(i2c)
MOTOR1 = 3
MOTOR2 = 4
#Initiate Communication from Sonar sensor
sensor_front = adafruit_hcsr04.HCSR04(trigger_pin=board.Pin('X3'), echo_pin=board.Pin('X4'))
sensor_back = adafruit_hcsr04.HCSR04(trigger_pin=board.Pin('X6'), echo_pin=board.Pin('X7'))
#Create minimum distance For Ultrasonic sensor
min_distance = sensor.distance(70)
button = pyb.switch()
def autonomy():
#no_problem = True
while (True):
if (button()):
dist_front = sensor1.distance(15)
dist_back = sensor2.distance(15)
if dist_front > min_distance:
print('Nothing can stop me!')
motors.speed(MOTOR1, 1500)
motors.speed(MOTOR2,-1500)
Here is the arduino code
/*!
* #file QuadMotorDriverShield.ino
* #brief QuadMotorDriverShield.ino Motor control program
*
* Every 2 seconds to control motor positive inversion
*
* #author linfeng(490289303#qq.com)
* #version V1.0
* #date 2016-4-5
*/
const int E1 = 3; ///<Motor1 Speed
const int E2 = 11;///<Motor2 Speed
const int E3 = 5; ///<Motor3 Speed
const int E4 = 6; ///<Motor4 Speed
const int M1 = 4; ///<Motor1 Direction
const int M2 = 12;///<Motor2 Direction
const int M3 = 8; ///<Motor3 Direction
const int M4 = 7; ///<Motor4 Direction
void M1_advance(char Speed) ///<Motor1 Advance
{
digitalWrite(M1,LOW);
analogWrite(E1,Speed);
}
void M2_advance(char Speed) ///<Motor2 Advance
{
digitalWrite(M2,HIGH);
analogWrite(E2,Speed);
}
void M3_advance(char Speed) ///<Motor3 Advance
{
digitalWrite(M3,LOW);
analogWrite(E3,Speed);
}
void M4_advance(char Speed) ///<Motor4 Advance
{
digitalWrite(M4,HIGH);
analogWrite(E4,Speed);
}
void M1_back(char Speed) ///<Motor1 Back off
{
digitalWrite(M1,HIGH);
analogWrite(E1,Speed);
}
void M2_back(char Speed) ///<Motor2 Back off
{
digitalWrite(M2,LOW);
analogWrite(E2,Speed);
}
void M3_back(char Speed) ///<Motor3 Back off
{
digitalWrite(M3,HIGH);
analogWrite(E3,Speed);
}
void M4_back(char Speed) ///<Motor4 Back off
{
digitalWrite(M4,LOW);
analogWrite(E4,Speed);
}
void setup() {
for(int i=3;i<9;i++)
pinMode(i,OUTPUT);
for(int i=11;i<13;i++)
pinMode(i,OUTPUT);
}
void loop() {
M1_advance(100);
M2_advance(100);
M3_advance(100);
M4_advance(100);
delay(2000); ///<Delay 2S
M1_back(100);
M2_back(100);
M3_back(100);
M4_back(100);
delay(2000); ///<Delay 2S
}
Here's attempt one. Consider using fuses until we're certain this is how to connect a DFRobot Motor HAT to a pyboard.
The connection point on the motor hat is the green digital bus.
import pyb
# don't use timers 2,3,5,6
'''
connect:
pyboard Motor Hat
X1 4
X3 3
GND GND
'''
FREQ = 50
backward = pyb.Pin('X1' ,pyb.Pin.OUT_PP)
speed = pyb.Timer(9, freq=FREQ).channel(1, pyb.Timer.PWM,\
pin = pyb.Pin('X3'))
while True:
backward.high()
for percent in range(100):
speed.pulse_width_percent(percent + 1)
pyb.delay(10)
speed.pulse_width_percent(0)
backward.low()
for percent in range(100):
speed.pulse_width_percent(percent + 1)
pyb.delay(10)
speed.pulse_width_percent(0)
I've guessed FREQ to be 50Hz it's that for many servos and i'm guessing arduino uses this as a default value for PWM (pulse width modulation).
Connect a motor to connector M1 and a battery to the motor hat's power socket. Don't connect to v+ on the pyboard. Power your pyboard with it's own power source. You motor hat probably creates a lot of electrical noise.
The motor should go backwards speeding up then suddenly stopping before going forwards getting faster then suddenly stop.
good luck
I am trying to communicate via my laptop to my arduino using the USB serial port. I am using Python 3.6, with the serial package. The simplified version of my Python code is :
import serial
import time
with serial.Serial(port="COM3", baudrate=9600) as ser:
time.sleep(2)
while True:
x, y, angle = detectAndDisplay(frame, face_cascade, eyes_cascade)
if x is not None:
ser.write((str(x * 100 // 177) + "/n").encode())
ser.write((str(y * 100 // 133) + "/n").encode())
if cv.waitKey(10) == 27:
break
Where the function detectAndDisplay() returns three int values. The values x, y are scaled to be between 0 and 180. I want to send the values x, y to the arduino, which has the following simplified code:
#include <PID_v1.h>
#include <Servo.h>
Servo Servo_1;
Servo Servo_2;
double Setpoint_1 = 90;
double Input_1;
double Output_1;
double Setpoint_2 = 90;
double Input_2;
double Output_2;
double Kp_1 = 0.022;
double Ki_1 = 0.012;
double Kd_1 = 0;
double Kp_2 = 0.032;
double Ki_2 = 0.022;
double Kd_2 = 0;
PID PID1(&Input_1, &Output_1, &Setpoint_1, Kp_1, Ki_1, Kd_1, DIRECT);
PID PID2(&Input_2, &Output_2, &Setpoint_2, Kp_2, Ki_2, Kd_2, DIRECT);
int serialCount = 0;
int serialInArray[2];
int posX = 90;
int posY = 90;
int errorX;
int errorY;
void setup() {
Serial.begin(9600);
Servo_1.attach(32);
Servo_2.attach(34);
PID1.SetMode(AUTOMATIC);
PID1.SetSampleTime(1);
PID1.SetOutputLimits(-35, 35);
PID2.SetMode(AUTOMATIC);
PID2.SetSampleTime(1);
PID2.SetOutputLimits(-35, 35);
Servo_1.write(90);
Servo_2.write(90);
}
void loop() {
while(Serial.available() == 0);
serialInArray[serialCount] = (Serial.read());
serialCount++;
if (serialCount > 1){
Input_1 = serialInArray[1];
Input_2 = serialInArray[0];
PID1.Compute();
PID2.Compute();
posX = posX + Output_2;
posY = posY + Output_1;
Servo_1.write(posX);
Servo_2.write(posY);
serialCount = 0;
}
}
Where I will use the values of posX and posY as input for servo motors. However, what I notice is that input is received on the arduino because it starts doing something as soon as the python script is started. However, the servo motors start turning to zero as soon as the input is received. This behavior is independent of the value that I am sending. What am I missing or what am I doing wrong?